from PySide6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                             QLabel, QLineEdit, QPushButton, QProgressBar, 
                             QTableWidget, QTableWidgetItem, QFileDialog, 
                             QTabWidget, QSpinBox, QDoubleSpinBox, QGroupBox, 
                             QDialog, QFormLayout, QMenu, QMessageBox, QTextBrowser,
                             QComboBox, QStyledItemDelegate, QSplitter, QGridLayout,
                             QHeaderView, QStyle, QProgressDialog)
from PySide6.QtCore import Qt, QTimer, Signal, Slot, QByteArray
from PySide6.QtGui import QClipboard, QPixmap, QImage, QPainter, QColor
from PySide6.QtWidgets import QApplication
import json
import os
from pathlib import Path
from typing import Dict, Optional, List, Tuple
from app.models.process_config import ProcessConfig
from app.models.task_manager import TaskManager, ProcessResult  # 添加 ProcessResult
from app.gui.image_preview import ImagePreviewDialog
from app.gui.charts import TaskStatsChart
import subprocess
from PIL import Image
import io
import cv2
from datetime import datetime
import numpy as np
import time
import shutil
import logging
import sys
import glob
import threading
from app.models.db import DBConnection
from app.models.image_processor import ImageProcessor

class MainWindow(QMainWindow):
    # 定义信号
    task_created = Signal(str)  # 任务创建成功信号
    task_create_failed = Signal(str)  # 任务创建失败信号
    progress_dialog_close = Signal()  # 关闭进度对话框信号
    
    def __init__(self):
        try:
            super().__init__()
            self.logger = logging.getLogger(__name__)
            self.logger.info("开始初始化主窗口")
            
            # 设置基本窗口属性
            self.setWindowTitle("LoRA训练图片筛选工具")
            self.setMinimumSize(1200, 800)
            self.logger.info("设置窗口基本属性完成")
            
            try:
                # 初始化分页相关属性
                self.page_size = 20
                self.current_page = 1
                self.passed_page_combo = None
                self.filtered_page_combo = None
                self.logger.info("初始化分页属性完成")
                
                # 1. 初始化基础配置和目录
                self._init_base_config()
                self.logger.info("初始化基础配置完成")
                
                # 2. 创建任务管理器
                self.task_manager = TaskManager(self.config)
                self.logger.info("创建任务管理器完成")
                
                # 3. 创建 GUI 组件
                self._init_gui_components()
                self.logger.info("初始化GUI组件完成")
                
                # 4. 设置窗口状态
                self.showMaximized()
                self.logger.info("设置窗口最大化完成")
                
                # 5. 等待 GUI 事件处理完成
                QApplication.processEvents()
                self.logger.info("GUI事件处理完成")
                
                # 6. 加载数据：任务列表，任务统计信息，通过和未通过的图片列表
                self.load_data()
                
                # 连接信号
                self.task_manager.update_task_stats.connect(self.update_task_stats)

            except Exception as e:
                self.logger.error(f"主窗口初始化过程中出错: {e}", exc_info=True)
                raise
                
        except Exception as e:
            self.logger.error(f"主窗口初始化失败: {e}", exc_info=True)
            QMessageBox.critical(self, "错误", f"初始化失败: {str(e)}")

    def load_data(self):
        """加载数据"""
        # 1. 加载任务列表
        tasks = self.load_task_data()

        # 2. 选择第一个任务
        self.current_task_id = tasks[0]['task_id']
        
        # 3. 更新统计信息
        self.update_task_stats(self.current_task_id)
        
        # 4. 更新分页信息
        self.update_pagination("passed", self.current_task_id)
        self.update_pagination("filtered", self.current_task_id)

        # 5. 加载当前页数据(未通过的图片列表)
        self.load_handle_result_data(self.current_task_id)
        return


    def create_results_group(self):
        """创建结果显示区域"""
        group = QGroupBox("处理结果")
        layout = QVBoxLayout(group)
        
        # 添加统计信息到表格上方
        self.stats_info = QLabel()
        self.stats_info.setAlignment(Qt.AlignLeft)  # 居中对齐
        self.stats_info.setStyleSheet("""
            QLabel {
                padding: 10px;
                margin: 0 0 10px 0;  # 添加底部间距
                background-color: #f8f9fa;
                border: 1px solid #dee2e6;
                border-radius: 4px;
                font-size: 14px;
            }
        """)
        layout.addWidget(self.stats_info)
        
        # 创建表格布局
        tables_layout = QHBoxLayout()
        
        # 通过组
        passed_group = QGroupBox("通过")
        passed_layout = QVBoxLayout(passed_group)
        
        # 通过表格
        self.passed_table = QTableWidget()
        self.setup_table(self.passed_table, True)
        passed_layout.addWidget(self.passed_table)
        
        # 通过列表分页
        self.passed_page_widget = self.create_page_widget("passed")
        passed_layout.addWidget(self.passed_page_widget)
        
        tables_layout.addWidget(passed_group)
        
        # 未通过组
        filtered_group = QGroupBox("未通过")
        filtered_layout = QVBoxLayout(filtered_group)
        
        # 添加表格
        self.filtered_table = QTableWidget()
        self.setup_table(self.filtered_table, False)
        filtered_layout.addWidget(self.filtered_table)
        
        # 未通过列表分页
        self.filtered_page_widget = self.create_page_widget("filtered")
        filtered_layout.addWidget(self.filtered_page_widget)
        
        tables_layout.addWidget(filtered_group)
        
        # 添加表格布局到主布局
        layout.addLayout(tables_layout)
        
        return group

    def setup_table(self, table: QTableWidget, is_passed: bool):
        """设置表格"""
        try:
            self.logger.info(f"开始设置表格: {'通过' if is_passed else '未通过'}")
            
            # 设置列
            if is_passed:
                columns = ['缩略图', '文件名', '尺寸', '大小', '质量分数', '详细分数', '人脸比例', '操作']
                # 设置可排序的列
                sortable_columns = {
                    2: 'size',          # 尺寸列
                    3: 'filesize',      # 大小列
                    4: 'quality',       # 质量分数列
                    5: 'detail',        # 详细分数列
                    6: 'face_ratio'     # 人脸比例列
                }
            else:
                columns = ['缩略图', '文件名', '尺寸', '大小', '过滤原因', '备注', '操作']
                # 设置可排序的列
                sortable_columns = {
                    2: 'size',          # 尺寸列
                    3: 'filesize',      # 大小列
                    4: 'filter_reason'  # 过滤原因列
                }
            
            # 保存排序配置
            setattr(table, 'sortable_columns', sortable_columns)
            setattr(table, 'current_sort_column', None)
            setattr(table, 'current_sort_order', Qt.AscendingOrder)
            
            # 启用排序
            table.setSortingEnabled(True)
            
            # 连接排序信号
            table.horizontalHeader().sectionClicked.connect(
                lambda col: self.on_header_clicked(table, col)
            )
            
            table.setColumnCount(len(columns))
            table.setHorizontalHeaderLabels(columns)
            
            # 设置列宽
            header = table.horizontalHeader()
            
            # 缩略图列
            header.setSectionResizeMode(0, QHeaderView.Fixed)
            table.setColumnWidth(0, 120)
            
            # 文件名列
            header.setSectionResizeMode(1, QHeaderView.Fixed)
            table.setColumnWidth(1, 200)
            
            # 尺寸列
            header.setSectionResizeMode(2, QHeaderView.Fixed)
            table.setColumnWidth(2, 100)
            
            # 大小列
            header.setSectionResizeMode(3, QHeaderView.Fixed)
            table.setColumnWidth(3, 80)
            
            if is_passed:
                # 质量分数列
                header.setSectionResizeMode(4, QHeaderView.Fixed)
                table.setColumnWidth(4, 100)
                
                # 详细分数列
                header.setSectionResizeMode(5, QHeaderView.Fixed)
                table.setColumnWidth(5, 200)
                
                # 人脸比例列
                header.setSectionResizeMode(6, QHeaderView.Fixed)
                table.setColumnWidth(6, 100)
                
                # 操作列
                header.setSectionResizeMode(7, QHeaderView.Fixed)
                table.setColumnWidth(7, 200)
            else:
                # 过滤原因列
                header.setSectionResizeMode(4, QHeaderView.Fixed)
                table.setColumnWidth(4, 200)
                
                # 备注列
                header.setSectionResizeMode(5, QHeaderView.Stretch)
                
                # 操作列
                header.setSectionResizeMode(6, QHeaderView.Fixed)
                table.setColumnWidth(6, 120)
            
            # 设置表格属性
            table.setSelectionBehavior(QTableWidget.SelectRows)
            table.setSelectionMode(QTableWidget.SingleSelection)
            table.setEditTriggers(QTableWidget.NoEditTriggers)
            table.verticalHeader().setVisible(False)
            
            # 设置缩略图代理
            table.setItemDelegateForColumn(0, ThumbnailDelegate(self))
            
            # 连接双击信号
            table.cellDoubleClicked.connect(
                lambda row, col: self.preview_image(table, row) if col == 0 else None
            )
            
            # 设置行高
            table.verticalHeader().setDefaultSectionSize(120)
            
            # 设置表格样式
            table.setStyleSheet("""
                QTableWidget {
                    gridline-color: #d6d6d6;
                    background-color: white;
                    alternate-background-color: #f8f9fa;
                    selection-background-color: #0078d4;
                    selection-color: white;
                    color: black;
                }
                QTableWidget::item {
                    padding: 5px;
                    border: none;
                    color: black;
                }
                QHeaderView::section {
                    background-color: #f0f0f0;
                    padding: 5px;
                    border: none;
                    border-right: 1px solid #d6d6d6;
                    border-bottom: 1px solid #d6d6d6;
                    color: black;
                }
            """)
            
        except Exception as e:
            self.logger.error(f"设置表格失败: {e}", exc_info=True)

    def on_header_clicked(self, table: QTableWidget, column: int):
        """处理表头点击事件"""
        try:
            # 获取可排序列配置
            sortable_columns = getattr(table, 'sortable_columns', {})
            if column not in sortable_columns:
                return
                
            # 获取当前排序状态
            current_column = getattr(table, 'current_sort_column', None)
            current_order = getattr(table, 'current_sort_order', Qt.AscendingOrder)
            
            # 确定新的排序顺序
            if column == current_column:
                new_order = Qt.DescendingOrder if current_order == Qt.AscendingOrder else Qt.AscendingOrder
            else:
                new_order = Qt.AscendingOrder
            
            # 更新排序状态
            setattr(table, 'current_sort_column', column)
            setattr(table, 'current_sort_order', new_order)
            
            # 执行排序
            self.sort_table(table, column, new_order)
            
        except Exception as e:
            self.logger.error(f"处理表头点击失败: {e}", exc_info=True)

    def sort_table(self, table: QTableWidget, column: int, order: Qt.SortOrder):
        """排序表格"""
        try:
            # 获取排序列类型
            sortable_columns = getattr(table, 'sortable_columns', {})
            sort_type = sortable_columns[column]
            
            # 获取所有行数据
            rows = []
            for row in range(table.rowCount()):
                row_data = []
                for col in range(table.columnCount()):
                    item = table.item(row, col)
                    row_data.append(item.text() if item else '')
                rows.append(row_data)
            
            # 定义排序键函数
            def get_sort_key(row_data):
                value = row_data[column]
                if sort_type == 'size':
                    # 尺寸格式: "1920x1080"
                    try:
                        w, h = map(int, value.split('x'))
                        return w * h
                    except:
                        return 0
                elif sort_type == 'filesize':
                    # 大小格式: "1.5 MB"
                    try:
                        size = float(value.split()[0])
                        return size
                    except:
                        return 0
                elif sort_type == 'quality':
                    # 质量分数
                    try:
                        return float(value)
                    except:
                        return 0
                elif sort_type == 'face_ratio':
                    # 人脸比例
                    try:
                        return float(value)
                    except:
                        return 0
                else:
                    return value
            
            # 排序
            rows.sort(
                key=get_sort_key,
                reverse=(order == Qt.DescendingOrder)
            )
            
            # 更新表格
            table.setSortingEnabled(False)  # 临时禁用排序以提高性能
            for row_idx, row_data in enumerate(rows):
                for col_idx, cell_data in enumerate(row_data):
                    if col_idx != 0:  # 跳过缩略图列
                        item = QTableWidgetItem(cell_data)
                        table.setItem(row_idx, col_idx, item)
            table.setSortingEnabled(True)
            
        except Exception as e:
            self.logger.error(f"排序表格失败: {e}", exc_info=True)

    def load_task_data(self) -> list[dict]: 
        """加载任务数据"""
        try:
            start_time = time.time()
            
            # 1. 获取任务列表
            sql = "SELECT * FROM tasks ORDER BY created_at DESC"
            tasks = DBConnection.execute(sql, fetch=True)
            
            if not tasks:
                return
                
            # 2. 更新任务列表
            self.update_task_list(tasks)

            return tasks
        except Exception as e:
            self.logger.error(f"加载任务数据失败: {e}", exc_info=True)

    def update_page_info(self):
        """更新分页信息"""
        try:
            if hasattr(self, 'current_task_id'):
                # 获取通过和未通过的结果数量
                # 查询数据库success_results和failed_results 
                sql = "SELECT * FROM success_results where task_id = %s"
                success_results = DBConnection.execute(sql, (self.current_task_id,), fetch=True)
                sql = "SELECT * FROM failed_results where task_id = %s"
                failed_results = DBConnection.execute(sql, (self.current_task_id,), fetch=True)
                passed_count = len(success_results)
                filtered_count = len(failed_results)
                
                # 更新通过列表分页
                if passed_count > 0:
                    page_combo = self.passed_page_widget.findChild(QComboBox)
                    if page_combo:
                        page_combo.clear()
                        total_pages = (passed_count + self.page_size - 1) // self.page_size
                        page_combo.addItems([str(i) for i in range(1, total_pages + 1)])
                        
                    page_label = self.passed_page_widget.findChild(QLabel)
                    if page_label:
                        page_label.setText(f"共 {total_pages} 页")
                
                # 更新未通过列表分页
                if filtered_count > 0:
                    page_combo = self.filtered_page_widget.findChild(QComboBox)
                    if page_combo:
                        page_combo.clear()
                        total_pages = (filtered_count + self.page_size - 1) // self.page_size
                        page_combo.addItems([str(i) for i in range(1, total_pages + 1)])
                        
                    page_label = self.filtered_page_widget.findChild(QLabel)
                    if page_label:
                        page_label.setText(f"共 {total_pages} 页")
                
                self.logger.info(f"更新分页信息完成: 通过 {passed_count} 条，未通过 {filtered_count} 条")
                
        except Exception as e:
            self.logger.error(f"更新分页信息失败: {e}", exc_info=True)

    def _init_base_config(self):
        """初始化基础配置"""
        try:
            self.logger.info("开始初始化基础配置")
            
            # 初始化配置目录
            self.config_dir = Path.home() / '.lora_filter'
            self.config_dir.mkdir(parents=True, exist_ok=True)
            
            # 初始化配置文件路径
            self.config_file = self.config_dir / 'config.json'
            self.tasks_file = self.config_dir / 'tasks.json'
            self.recent_dirs_file = self.config_dir / 'recent_dirs.json'
            
            # 加载配置
            self.init_config()
            self.init_directories()
            
            self.logger.info("基础配置初始化完成")
            
        except Exception as e:
            self.logger.error(f"初始化基础配置失败: {e}", exc_info=True)
            raise

    def _init_gui_components(self):
        """初始化 GUI 组件"""
        try:
            self.logger.info("开始初始化GUI组件")
            
            # 创建主布局
            central_widget = QWidget()
            self.setCentralWidget(central_widget)
            main_layout = QVBoxLayout(central_widget)
            
            # 创建垂直分割器
            self.splitter = QSplitter(Qt.Vertical)
            main_layout.addWidget(self.splitter)
            
            # 创建目录设置区域
            dir_group = self.create_directory_group()
            self.splitter.addWidget(dir_group)
            self.logger.info("创建目录设置区域完成")
            
            # 创建任务列表区域
            task_group = self.create_task_group()
            self.splitter.addWidget(task_group)
            self.logger.info("创建任务列表区域完成")
            
            # 创建结果显示区域
            results_group = self.create_results_group()
            self.splitter.addWidget(results_group)
            self.logger.info("创建结果显示区域完成")
            
            # 设置分割器初始大小比例
            total_height = self.height()
            self.splitter.setSizes([
                int(total_height * 0.15),  # 目录设置区域 15%
                int(total_height * 0.15),  # 任务列表区域 15%
                int(total_height * 0.70)   # 处理结果区域 70%
            ])
            
            # 添加状态栏
            self.statusBar().showMessage("就绪")
            
            self.logger.info("GUI组件初始化完成")
            
            # 连接任务表格的双击信号
            self.task_table.cellDoubleClicked.connect(self.on_task_table_double_clicked)

            # 连接任务表格的点击信号
            self.task_table.cellClicked.connect(self.on_task_table_item_clicked)
            
        except Exception as e:
            self.logger.error(f"初始化GUI组件失败: {e}", exc_info=True)
            raise

    def _init_data_and_background(self):
        """初始化数据和后台任务"""
        try:
            self.logger.info("开始初始化数据和后台任务")
            
            # 初始化分页相关变量
            self.page_size = 20
            self.current_page = 1
            
            # 加载任务数据
            self.logger.info("准备加载任务数据")
            self.logger.info(f"任务管理器状态: {self.task_manager}")
            self.logger.info(f"任务管理器属性: {dir(self.task_manager)}")
            
            try:
                self.load_tasks()
            except Exception as e:
                self.logger.error(f"加载任务数据\n{type(e).__name__}: {str(e)}")
            
            self.logger.info("数据和后台任务初始化完成")
            
        except Exception as e:
            self.logger.error(f"初始化数据和后台任务失败: {e}", exc_info=True)

    def init_config(self):
        """初始化配置"""
        try:
            self.logger.info("开始加载配置")
            self.config = ProcessConfig()  # 创建默认配置
            
            if self.config_file.exists():
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    # 更新配置，保留默认值
                    for key, value in data.items():
                        if hasattr(self.config, key):
                            setattr(self.config, key, value)
            
            self.logger.info("配置加载成功")
        except Exception as e:
            self.logger.error(f"加载配置失败: {e}", exc_info=True)
            self.config = ProcessConfig()  # 使用默认配置

    def init_directories(self):
        """初始化目录"""
        try:
            # 创建必要的目录
            self.cache_dir = self.config_dir / 'cache'
            self.cache_dir.mkdir(exist_ok=True)
            
            self.thumbnail_dir = self.config_dir / 'thumbnails'
            self.thumbnail_dir.mkdir(exist_ok=True)
            
            # 加载最近使用的目录
            self.recent_dirs_file = self.config_dir / 'recent_dirs.json'
            self.recent_dirs = {
                'input': '',
                'output': ''
            }
            
            if self.recent_dirs_file.exists():
                try:
                    with open(self.recent_dirs_file, 'r', encoding='utf-8') as f:
                        self.recent_dirs = json.load(f)
                        
                    # 设置上次使用的目录
                    if self.recent_dirs.get('input'):
                        self.input_dir.setText(self.recent_dirs['input'])
                    if self.recent_dirs.get('output'):
                        self.output_dir.setText(self.recent_dirs['output'])
                        
                except Exception as e:
                    self.logger.error(f"加载目录记录失败: {e}", exc_info=True)
            
        except Exception as e:
            self.logger.error(f"初始化目录失败: {e}", exc_info=True)

    def load_tasks(self):
        """加载任务数据"""
        try:
            self.logger.info("开始加载任务数据")
            
            # 清空现有表格
            self.task_table.setRowCount(0)
            
            # 检查任务管理器是否已初始化
            if not hasattr(self, 'task_manager'):
                self.logger.error("任务管理器未初始化")
                return
                
            # 检查任务列表
            sql = "SELECT * FROM tasks"
            tasks = DBConnection.execute(sql, fetch=True)
            if not tasks or len(tasks) == 0:
                self.logger.info(f"任务列表为空或无效: {tasks}")
                return
                
            # 遍历任务管理器中的任务
            for task in tasks:
                try:
                    # 添加到任务列表
                    row = self.task_table.rowCount()
                    self.task_table.insertRow(row)
                    
                    # 设置基本信息
                    self.task_table.setItem(row, 0, QTableWidgetItem(task['task_id']))
                    self.task_table.setItem(row, 1, QTableWidgetItem(task['status']))
                    self.task_table.setItem(row, 2, QTableWidgetItem(str(task['processed_files'])))
                    self.task_table.setItem(row, 3, QTableWidgetItem(str(task['total_files'])))
                    self.task_table.setItem(row, 4, QTableWidgetItem(task['input_dir']))
                    self.task_table.setItem(row, 5, QTableWidgetItem(task['output_dir']))
                    
                    # 创建操作按钮容器
                    button_widget = QWidget()
                    button_layout = QHBoxLayout(button_widget)
                    button_layout.setContentsMargins(5, 0, 5, 0)
                    button_layout.setSpacing(5)
                    
                    # 创建暂停/继续按钮
                    status = task['status']
                    toggle_btn = QPushButton("暂停" if status == 'processing' else "继续")
                    toggle_btn.setFixedWidth(60)
                    toggle_btn.clicked.connect(lambda checked, tid=task['task_id']: self.toggle_task(tid))
                    toggle_btn.setStyleSheet("""
                        QPushButton {
                            background-color: #f0f0f0;
                            border: 1px solid #d0d0d0;
                            border-radius: 4px;
                            padding: 4px;
                        }
                        QPushButton:hover {
                            background-color: #e0e0e0;
                        }
                    """)
                    button_layout.addWidget(toggle_btn)
                    
                    # 创建删除按钮
                    delete_btn = QPushButton("删除")
                    delete_btn.setFixedWidth(60)
                    delete_btn.clicked.connect(lambda checked, tid=task['task_id']: self.delete_task(tid))
                    delete_btn.setStyleSheet("""
                        QPushButton {
                            background-color: #ff4d4d;
                            color: white;
                            border: none;
                            border-radius: 4px;
                            padding: 4px;
                        }
                        QPushButton:hover {
                            background-color: #ff3333;
                        }
                    """)
                    button_layout.addWidget(delete_btn)
                    
                    # 设置操作列
                    self.task_table.setCellWidget(row, 6, button_widget)
                except Exception as e:
                    self.logger.error(f"处理任务 {task['task_id']} 失败: {e}", exc_info=True)
                    continue
            
            self.logger.info(f"加载了 {self.task_table.rowCount()} 个任务")
            
        except Exception as e:
            self.logger.error(f"加载任务数据失败: {e}", exc_info=True)

    def start_update_timer(self):
        """启动更新定时器"""
        self.update_timer = QTimer()
        self.update_timer.timeout.connect(self.update_task_list)
        self.update_timer.start(1000)  # 每秒更新一次

    def setup_task_table(self):
        """设置任务表格"""
        self.task_table.setColumnCount(9)
        self.task_table.setHorizontalHeaderLabels([
            "任务ID", "状态", "已处理", "总数", 
            "输入目录", "输出目录", "操作"
        ])
        
        # 设置列宽
        self.task_table.horizontalHeader().setStretchLastSection(False)
        self.task_table.setColumnWidth(0, 180)  # 任务ID
        self.task_table.setColumnWidth(1, 60)   # 状态
        self.task_table.setColumnWidth(2, 60)   # 已处理
        self.task_table.setColumnWidth(3, 100)  # 总数
        self.task_table.setColumnWidth(4, 150)  # 输入目录
        self.task_table.setColumnWidth(5, 150)  # 输出目录
        self.task_table.setColumnWidth(6, 150)  # 操作按钮
        
        # 设置表格属性
        self.task_table.setSelectionBehavior(QTableWidget.SelectRows)
        self.task_table.setSelectionMode(QTableWidget.SingleSelection)
        self.task_table.setShowGrid(True)
        self.task_table.setAlternatingRowColors(True)
        
        # 设置表头样式
        header = self.task_table.horizontalHeader()
        header.setStretchLastSection(True)
        header.setSectionResizeMode(0, QHeaderView.Fixed)
        header.setSectionResizeMode(1, QHeaderView.Fixed)
        header.setSectionResizeMode(2, QHeaderView.Fixed)
        header.setSectionResizeMode(3, QHeaderView.Fixed)
        header.setSectionResizeMode(4, QHeaderView.Fixed)
        header.setSectionResizeMode(5, QHeaderView.Fixed)
        header.setSectionResizeMode(6, QHeaderView.Fixed)
        
        # 添加选择事件
        self.task_table.itemSelectionChanged.connect(self.on_task_selected)
        
        # 添加双击事件
        self.task_table.cellDoubleClicked.connect(self.on_task_cell_double_clicked)


    def create_config_widget(self) -> QWidget:
        """创建配置页面"""
        widget = QWidget()
        layout = QVBoxLayout(widget)
        
        # 基础质量参数
        quality_group = QGroupBox("基础质量参数")
        quality_layout = QVBoxLayout(quality_group)
        
        # 质量阈值
        quality_threshold_layout = QHBoxLayout()
        self.quality_threshold = QSpinBox()
        self.quality_threshold.setRange(0, 100)
        self.quality_threshold.setValue(int(self.config.quality_threshold * 100))
        self.quality_threshold.valueChanged.connect(self.save_config)
        quality_threshold_layout.addWidget(QLabel("质量阈值:"))
        quality_threshold_layout.addWidget(self.quality_threshold)
        quality_threshold_layout.addWidget(QLabel("值越小表示质量越好，建议范围20-50"))
        quality_layout.addLayout(quality_threshold_layout)
        
        layout.addWidget(quality_group)
        
        # 人脸检测参数
        face_group = QGroupBox("人脸检测参数")
        face_layout = QVBoxLayout(face_group)
        
        # 人脸比例
        ratio_layout = QHBoxLayout()
        self.face_ratio_min = QDoubleSpinBox()
        self.face_ratio_min.setRange(0.05, 0.3)
        self.face_ratio_min.setSingleStep(0.01)
        self.face_ratio_min.setValue(self.config.face_ratio_min)
        self.face_ratio_max = QDoubleSpinBox()
        self.face_ratio_max.setRange(0.4, 0.9)
        self.face_ratio_max.setSingleStep(0.01)
        self.face_ratio_max.setValue(self.config.face_ratio_max)
        ratio_layout.addWidget(QLabel("人脸比例范围:"))
        ratio_layout.addWidget(self.face_ratio_min)
        ratio_layout.addWidget(QLabel("-"))
        ratio_layout.addWidget(self.face_ratio_max)
        face_layout.addLayout(ratio_layout)
        
        layout.addWidget(face_group)
        
        # 保存按钮
        save_btn = QPushButton("保存配置")
        save_btn.clicked.connect(self.save_config)
        layout.addWidget(save_btn)
        
        layout.addStretch()
        return widget

    def select_directory(self, dir_type: str):
        """选择目录"""
        try:
            dialog = QFileDialog()
            dialog.setFileMode(QFileDialog.Directory)
            dialog.setOption(QFileDialog.ShowDirsOnly, True)
            
            # 设置初始目录
            if self.recent_dirs.get(dir_type):
                dialog.setDirectory(self.recent_dirs[dir_type])
            
            if dialog.exec():
                selected_dir = dialog.selectedFiles()[0]
                if dir_type == 'input':
                    self.input_dir.setText(selected_dir)
                    self.update_directory_stats(selected_dir)
                else:
                    self.output_dir.setText(selected_dir)
                
                # 保存最近使用的目录
                self.save_recent_dirs()
                
                self.logger.info(f"选择{dir_type}目录: {selected_dir}")
                
        except Exception as e:
            self.logger.error(f"选择目录失败: {e}", exc_info=True)

    def update_directory_stats(self, directory: str):
        """更新目录统计信息"""
        try:
            # 统计图片文件
            image_files = []
            total_size = 0
            for ext in ['.jpg', '.jpeg', '.png']:
                files = glob.glob(os.path.join(directory, '**', f'*{ext}'), recursive=True)
                image_files.extend(files)
                total_size += sum(os.path.getsize(f) for f in files)
            
            # 格式化大小
            if total_size < 1024:
                size_text = f"{total_size}B"
            elif total_size < 1024 * 1024:
                size_text = f"{total_size/1024:.1f}KB"
            else:
                size_text = f"{total_size/1024/1024:.1f}MB"
            
            stats_text = f"共 {len(image_files)} 个图片文件，总大小 {size_text}"
            self.input_stats.setText(stats_text)
            
        except Exception as e:
            self.logger.error(f"更新目录统计失败: {e}")
            self.input_stats.setText(f"统计失败: {str(e)}")

    def format_size(self, size: int) -> str:
        """格式化文件大小"""
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size < 1024:
                return f"{size:.1f} {unit}"
            size /= 1024
        return f"{size:.1f} TB"

    def validate_directories(self) -> bool:
        """验证目录设置"""
        input_dir = self.input_dir.text()
        output_dir = self.output_dir.text()
        
        if not input_dir or not output_dir:
            QMessageBox.warning(self, "验证失败", "请选择输入和输出目录")
            return False
        
        if not os.path.exists(input_dir):
            QMessageBox.warning(self, "验证失败", "输入目录不存在")
            return False
        
        # 检查输出目录是否存在，不存在则询问是否创建
        if not os.path.exists(output_dir):
            reply = QMessageBox.question(
                self,
                "创建目录",
                f"输出目录 {output_dir} 不存在，是否创建？",
                QMessageBox.Yes | QMessageBox.No
            )
            
            if reply == QMessageBox.Yes:
                try:
                    os.makedirs(output_dir)
                except Exception as e:
                    QMessageBox.critical(self, "错误", f"创建目录失败: {str(e)}")
                    return False
            else:
                return False
        
        return True

    def create_task(self):
        """创建新任务"""
        input_dir = self.input_dir.text()
        output_dir = self.output_dir.text()
        
        if not input_dir or not output_dir:
            QMessageBox.warning(self, "错误", "请选择输入和输出目录")
            return
        
        # 检查输出目录是否已被使用      
        sql = "SELECT * FROM tasks"
        tasks = DBConnection.execute(sql, fetch=True)
        for task_id, task in tasks.items():
            if os.path.normpath(task['output_dir']) == os.path.normpath(output_dir):
                QMessageBox.warning(self, "错误", "该输出目录已被其他任务使用")
                return
        
        try:
            # 创建任务，传入当前配置
            task_id = self.task_manager.create_task(input_dir, output_dir, self.config)
            if task_id:
                # 添加到任务列表
                task = self.task_manager.get_task(task_id)
                self.add_task_to_table(task)
                
                # 保存任务数据
                self.save_tasks()
                
                # 更新状态栏
                self.statusBar().showMessage("任务创建成功")
                
                # 选中新创建的任务
                for row in range(self.task_table.rowCount()):
                    if self.task_table.item(row, 0).text() == task_id:
                        self.task_table.selectRow(row)
                        break
        
        except Exception as e:
            print(f"创建任务失败: {e}")
            QMessageBox.warning(self, "错误", f"创建任务失败: {str(e)}")

    def add_task_to_table(self, task):
        """添加任务到表格"""
        try:
            self.logger.info(f"开始添加任务到表格: {task['task_id']}")
            row = self.task_table.rowCount()
            self.task_table.insertRow(row)
            
            # 创建所有单元格项目
            items = [
                QTableWidgetItem(task['task_id']),
                QTableWidgetItem(self.get_status_text(task['status'])),
                QTableWidgetItem("0"),
                QTableWidgetItem(str(task['total_files'])),
                QTableWidgetItem(task['input_dir']),
                QTableWidgetItem(task['output_dir'])
            ]
            
            # 设置每个单元格
            for col, item in enumerate(items):
                self.task_table.setItem(row, col, item)
            
            # 添加操作按钮
            operation_widget = QWidget()
            operation_layout = QHBoxLayout(operation_widget)
            operation_layout.setContentsMargins(5, 0, 5, 0)
            
            # 暂停/继续按钮
            pause_btn = QPushButton("暂停" if task['status'] == 'processing' else "继续")
            pause_btn.clicked.connect(lambda: self.toggle_task(task['task_id']))
            pause_btn.setStyleSheet(self.get_button_style(True))  # 使用蓝色样式
            operation_layout.addWidget(pause_btn)
            
            # 删除按钮
            delete_btn = QPushButton("删除")
            delete_btn.clicked.connect(lambda: self.delete_task(task['task_id']))
            delete_btn.setStyleSheet(self.get_button_style(True))  # 使用蓝色样式
            operation_layout.addWidget(delete_btn)
            
            operation_layout.addStretch()
            self.task_table.setCellWidget(row, 8, operation_widget)
            
            self.logger.info(f"任务添加完成: {task['task_id']}")
            
        except Exception as e:
            self.logger.error(f"添加任务到表格失败: {e}", exc_info=True)

    def delete_task(self, task_id: str):
        """删除任务"""
        try:
            reply = QMessageBox.question(
                self, "确认删除",
                "确定要删除该任务吗？",
                QMessageBox.Yes | QMessageBox.No,
                QMessageBox.No
            )
            
            if reply == QMessageBox.Yes:
                self.task_manager.remove_task(task_id)
                
                # 从表格中删除
                for row in range(self.task_table.rowCount()):
                    if self.task_table.item(row, 0).text() == task_id:
                        self.task_table.removeRow(row)
                        break
                
                # 如果删除的是当前选中的任务，清空结果显示
                if hasattr(self, 'current_task_id') and self.current_task_id == task_id:
                    self.current_task_id = None
                    self.passed_table.setRowCount(0)
                    self.filtered_table.setRowCount(0)
                    self.stats_info.clear()
                
                # 从数据库中删除任务
                sql = "DELETE FROM tasks WHERE task_id = %s"
                DBConnection.execute(sql, (task_id,))   
                
                self.statusBar().showMessage("任务已删除")
                
        except Exception as e:
            self.logger.error(f"删除任务失败: {e}", exc_info=True)
            QMessageBox.warning(self, "错误", f"删除任务失败: {str(e)}")

    def get_status_text(self, status: str) -> str:
        """获取状态文本"""
        status_map = {
            'pending': '等待中',
            'processing': '处理中',
            'paused': '已暂停',
            'completed': '已完成'
        }
        return status_map.get(status, status)

    def load_config(self):
        """加载配置到界面"""
        try:
            # 更新界面控件的值
            self.quality_threshold.setValue(int(self.config.quality_threshold * 100))
            self.face_ratio_min.setValue(self.config.face_ratio_min)
            self.face_ratio_max.setValue(self.config.face_ratio_max)
            
        except Exception as e:
            print(f"加载配置到界面失败: {e}")

    def save_config(self):
        """保存配置"""
        try:
            # 从界面获取值
            self.config.quality_threshold = self.quality_threshold.value() / 100
            self.config.face_ratio_min = self.face_ratio_min.value()
            self.config.face_ratio_max = self.face_ratio_max.value()
            
            # 保存到文件
            self.config_file.parent.mkdir(parents=True, exist_ok=True)
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(self.config.__dict__, f, indent=2)
            
            print("配置保存成功")
            
        except Exception as e:
            print(f"保存配置失败: {e}")

    def create_toolbar(self):
        """创建工具栏"""
        toolbar = self.addToolBar("工具栏")
        
        # 刷新按钮
        refresh_action = toolbar.addAction("刷新")
        refresh_action.triggered.connect(self.refresh_view)
        
        # 统计按钮
        stats_action = toolbar.addAction("统计")
        stats_action.triggered.connect(self.show_stats)
        
        # 帮助按钮
        help_action = toolbar.addAction("帮助")
        help_action.triggered.connect(self.show_help)

    def show_task_context_menu(self, pos):
        """显示任务右键菜单"""
        menu = QMenu(self)
        
        row = self.task_table.rowAt(pos.y())
        if row >= 0:
            task_id = self.task_table.item(row, 0).text()
            task = self.task_manager.get_task(task_id)
            
            if task:
                # 查看详情
                details_action = menu.addAction("查看详情")
                details_action.triggered.connect(lambda: self.show_task_details(task))
                
                # 打开输出目录
                open_output_action = menu.addAction("打开输出目录")
                open_output_action.triggered.connect(lambda: self.open_directory(task['output_dir']))
                
                menu.addSeparator()
                
                # 暂停/继续
                if task['status'] == 'processing':
                    pause_action = menu.addAction("暂停")
                    pause_action.triggered.connect(lambda: self.pause_task(task_id))
                elif task['status'] == 'paused':
                    resume_action = menu.addAction("继续")
                    resume_action.triggered.connect(lambda: self.resume_task(task_id))
                
                # 删除任务
                if task['status'] in ['completed', 'failed']:
                    delete_action = menu.addAction("删除")
                    delete_action.triggered.connect(lambda: self.delete_task(task_id))
        
        menu.exec_(self.task_table.viewport().mapToGlobal(pos))

    def show_result_context_menu(self, pos):
        """显示结果右键菜单"""
        table = self.sender()
        menu = QMenu(self)
        
        row = table.rowAt(pos.y())
        if row >= 0:
            filename = table.item(row, 0).text()
            
            # 预览图片
            preview_action = menu.addAction("预览")
            preview_action.triggered.connect(lambda: self.preview_image(filename))
            
            # 打开所在目录
            open_dir_action = menu.addAction("打开所在目录")
            open_dir_action.triggered.connect(lambda: self.locate_image(filename))
            
            # 复制文件名
            copy_action = menu.addAction("复制文件名")
            copy_action.triggered.connect(lambda: QApplication.clipboard().setText(filename))
        
        menu.exec_(table.viewport().mapToGlobal(pos))

    def show_task_details(self, task):
        """显示任务详情"""
        dialog = QDialog(self)
        dialog.setWindowTitle(f"任务详情 - {task['task_id']}")
        dialog.resize(800, 600)
        
        layout = QVBoxLayout(dialog)
        
        # 创建选项卡
        tab_widget = QTabWidget()
        layout.addWidget(tab_widget)
        
        # 基本信息选项卡
        info_tab = QWidget()
        info_layout = QVBoxLayout(info_tab)
        
        # 基本信息
        info_group = QGroupBox("基本信息")
        info_layout.addWidget(info_group)
        
        info_layout.addRow("输入目录:", QLabel(task['input_dir']))
        info_layout.addRow("输出目录:", QLabel(task['output_dir']))
        info_layout.addRow("开始时间:", QLabel(task['start_time'].strftime("%Y-%m-%d %H:%M:%S") if task['start_time'] else "-"))
        info_layout.addRow("结束时间:", QLabel(task['end_time'].strftime("%Y-%m-%d %H:%M:%S") if task['end_time'] else "-"))
        info_layout.addRow("处理时间:", QLabel(f"{task['duration']:.1f}秒"))
        
        tab_widget.addTab(info_tab, "基本信息")
        
        # 统计图表选项卡
        charts_tab = QWidget()
        charts_layout = QHBoxLayout(charts_tab)
        
        # 添加饼图
        pie_chart = TaskStatsChart.create_pie_chart(task)
        pie_view = QChartView(pie_chart)
        pie_view.setRenderHint(QPainter.Antialiasing)
        charts_layout.addWidget(pie_view)
        
        # 添加柱状图
        bar_chart = TaskStatsChart.create_reasons_chart(task)
        bar_view = QChartView(bar_chart)
        bar_view.setRenderHint(QPainter.Antialiasing)
        charts_layout.addWidget(bar_view)
        
        tab_widget.addTab(charts_tab, "统计图表")
        
        # 添加关闭按钮
        close_btn = QPushButton("关闭")
        close_btn.clicked.connect(dialog.close)
        layout.addWidget(close_btn)
        
        dialog.exec_()

    def preview_image(self, filename: str):
        """预览图片"""
        # 查找当前选中的任务
        current_row = self.task_table.currentRow()
        if current_row < 0:
            return
        
        task_id = self.task_table.item(current_row, 0).text()
        task = self.task_manager.get_task(task_id)
        if not task:
            return
        
        # 确定图片路径
        if filename in task['results']:
            result = task['results'][filename]
            image_path = result['processed_path'] if result['status'] == 'success' else \
                        os.path.join(task['input_dir'], filename)
            
            if os.path.exists(image_path):
                dialog = ImagePreviewDialog(image_path, self)
                dialog.exec_()

    def open_directory(self, path: str):
        """打开目录"""
        try:
            if os.name == 'nt':  # Windows
                os.startfile(path)
            elif os.name == 'posix':  # macOS 和 Linux
                subprocess.run(['xdg-open' if os.name == 'posix' else 'open', path])
        except Exception as e:
            QMessageBox.warning(self, "错误", f"无法打开目录：{str(e)}")

    def locate_image(self, filename: str):
        """定位图片文件"""
        current_row = self.task_table.currentRow()
        if current_row < 0:
            return
        
        task_id = self.task_table.item(current_row, 0).text()
        task = self.task_manager.get_task(task_id)
        if not task:
            return
        
        # 确定图片路径
        if filename in task['results']:
            result = task['results'][filename]
            image_path = result['processed_path'] if result['status'] == 'success' else \
                        os.path.join(task['input_dir'], filename)
            
            if os.path.exists(image_path):
                # 打开文件所在目录并选中文件
                if platform.system() == "Windows":
                    subprocess.run(['explorer', '/select,', image_path])
                elif platform.system() == "Darwin":
                    subprocess.run(['open', '-R', image_path])
                else:
                    # Linux系统可能需要安装xdg-utils
                    subprocess.run(['xdg-open', os.path.dirname(image_path)])

    def export_results(self):
        """导出处理结果"""
        # 选择导出文件
        file_path, _ = QFileDialog.getSaveFileName(
            self,
            "导出结果",
            str(Path.home() / "处理结果.xlsx"),
            "Excel文件 (*.xlsx);;CSV文件 (*.csv)"
        )
        
        if not file_path:
            return
        
        try:
            if file_path.endswith('.xlsx'):
                self.export_to_excel(file_path)
            else:
                self.export_to_csv(file_path)
            
            self.statusBar().showMessage(f"结果已导出到: {file_path}")
            
            # 询问是否打开文件
            if QMessageBox.question(
                self,
                "导出完成",
                "结果导出完成，是否打开文件？",
                QMessageBox.Yes | QMessageBox.No
            ) == QMessageBox.Yes:
                self.open_directory(file_path)
            
        except Exception as e:
            QMessageBox.critical(self, "导出失败", f"导出结果失败: {str(e)}")

    def export_to_excel(self, file_path: str):
        """导出到Excel"""
        import pandas as pd
        from datetime import datetime
        
        # 收集所有任务的结果
        all_results = []
        
        for task in self.task_manager.get_all_tasks():
            for filename, result in task['results'].items():
                row = {
                    '任务ID': task['task_id'],
                    '文件名': filename,
                    '状态': self.get_status_text(result['status']),
                    '处理时间': result['timestamp'].strftime("%Y-%m-%d %H:%M:%S"),
                }
                
                # 添加分析结果
                if result.analysis:
                    row.update({
                        '人脸比例': f"{result['analysis']['face_ratio']:.1%}",
                        '偏航角': f"{result['analysis']['yaw']:.1f}°",
                        '俯仰角': f"{result['analysis']['pitch']:.1f}°",
                        '模糊度': f"{result['analysis']['blur']:.1f}",
                        '聚类ID': result['analysis'].get('cluster', '-')
                    })
                
                # 添加过滤原因
                if result.filter_reasons:
                    row['过滤原因'] = ', '.join(r.message for r in result.filter_reasons)
                
                all_results.append(row)
        
        # 创建DataFrame并保存
        df = pd.DataFrame(all_results)
        
        # 创建Excel写入器
        with pd.ExcelWriter(file_path, engine='openpyxl') as writer:
            # 写入结果表
            df.to_excel(writer, sheet_name='处理结果', index=False)
            
            # 获取工作簿
            workbook = writer.book
            worksheet = writer.sheets['处理结果']
            
            # 调整列宽
            for column in worksheet.columns:
                max_length = 0
                column = [cell for cell in column]
                for cell in column:
                    try:
                        if len(str(cell.value)) > max_length:
                            max_length = len(str(cell.value))
                    except:
                        pass
                adjusted_width = (max_length + 2)
                worksheet.column_dimensions[column[0].column_letter].width = adjusted_width

    def export_to_csv(self, file_path: str):
        """导出到CSV"""
        import csv
        from datetime import datetime
        
        with open(file_path, 'w', newline='', encoding='utf-8-sig') as f:
            writer = csv.writer(f)
            
            # 写入表头
            headers = ['任务ID', '文件名', '状态', '处理时间', '人脸比例', '偏航角', 
                      '俯仰角', '模糊度', '聚类ID', '过滤原因']
            writer.writerow(headers)
            
            # 写入数据
            for task in self.task_manager.get_all_tasks():
                for filename, result in task['results'].items():
                    row = [
                        task['task_id'],
                        filename,
                        self.get_status_text(result['status']),
                        result['timestamp'].strftime("%Y-%m-%d %H:%M:%S")
                    ]
                    
                    # 添加分析结果
                    if result.analysis:
                        row.extend([
                            f"{result['analysis']['face_ratio']:.1%}",
                            f"{result['analysis']['yaw']:.1f}°",
                            f"{result['analysis']['pitch']:.1f}°",
                            f"{result['analysis']['blur']:.1f}",
                            result['analysis'].get('cluster', '-')
                        ])
                    else:
                        row.extend(['-'] * 5)
                    
                    # 添加过滤原因
                    if result['filter_reasons']:
                        row.append(', '.join(r['message'] for r in result['filter_reasons']))
                    else:
                        row.append('')
                    
                    writer.writerow(row)

    def show_stats(self):
        """显示统计信息"""
        try:
            # 获取当前选中的任务
            current_row = self.task_table.currentRow()
            if current_row < 0:
                QMessageBox.warning(self, "提示", "请先选择一个任务")
                return
            
            task_id = self.task_table.item(current_row, 0).text()
            task = self.task_manager.get_task(task_id)
            if not task:
                return
            
            # 收集统计数据
            stats = {
                '总文件数': task['total_files'],
                '已处理': task['processed_files'],
                '通过数量': sum(1 for r in task['results'].values() if r['status'] == 'success'),
                '未通过数量': sum(1 for r in task['results'].values() if r['status'] == 'filtered'),
                '失败数量': sum(1 for r in task['results'].values() if r['status'] == 'failed'),
            }
            
            # 计算过滤原因分布
            reason_stats = {}
            for result in task['results'].values():
                if result['filter_reasons']:
                    for reason in result['filter_reasons']:
                        reason_stats[reason['message']] = reason_stats.get(reason['message'], 0) + 1
            
            # 创建统计对话框    
            dialog = QDialog(self)
            dialog.setWindowTitle("任务统计")
            dialog.setMinimumWidth(400)
            layout = QVBoxLayout(dialog)
            
            # 基本统计信息
            stats_group = QGroupBox("基本统计")
            stats_layout = QFormLayout(stats_group)
            for key, value in stats.items():
                stats_layout.addRow(f"{key}:", QLabel(str(value)))
            layout.addWidget(stats_group)
            
            # 过滤原因统计
            if reason_stats:
                reasons_group = QGroupBox("过滤原因分布")
                reasons_layout = QFormLayout(reasons_group)
                for reason, count in reason_stats.items():
                    reasons_layout.addRow(f"{reason}:", QLabel(str(count)))
                layout.addWidget(reasons_group)
            
            # 添加图表
            if hasattr(self, 'stats_chart'):
                chart_widget = TaskStatsChart(task)
                layout.addWidget(chart_widget)
            
            # 添加关闭按钮
            close_btn = QPushButton("关闭")
            close_btn.clicked.connect(dialog.accept)
            layout.addWidget(close_btn)
            
            dialog.exec_()
            
        except Exception as e:
            print(f"显示统计信息失败: {e}")
            QMessageBox.warning(self, "错误", f"显示统计信息失败: {str(e)}")

    def show_help(self):
        """显示帮助信息"""
        help_text = """
        <h3>LoRA图片筛选工具使用说明</h3>
        
        <h4>基本操作：</h4>
        <ul>
        <li>选择输入目录：包含需要筛选的图片</li>
        <li>选择输出目录：存放筛选结果</li>
        <li>点击"开始筛选"创建新任务</li>
        </ul>
        
        <h4>任务管理：</h4>
        <ul>
        <li>可以同时运行多个任务</li>
        <li>点击"暂停"/"继续"控制任务</li>
        <li>双击目录可以打开文件夹</li>
        </ul>
        
        <h4>结果查看：</h4>
        <ul>
        <li>通过/未通过的图片分开显示</li>
        <li>可以使用筛选条件过滤结果</li>
        <li>双击图片可以预览</li>
        <li>点击"纠正"可以修改分类结果</li>
        </ul>
        
        <h4>配置说明：</h4>
        <ul>
        <li>最小分辨率：低于此分辨率的图片会被过滤</li>
        <li>质量阈值：低于此值的图片会被过滤</li>
        <li>亮度均衡：对图片进行亮度调整</li>
        </ul>
        """
        
        dialog = QDialog(self)
        dialog.setWindowTitle("帮助")
        dialog.setMinimumSize(500, 400)
        layout = QVBoxLayout(dialog)
        
        help_browser = QTextBrowser()
        help_browser.setHtml(help_text)
        layout.addWidget(help_browser)
        
        close_btn = QPushButton("关闭")
        close_btn.clicked.connect(dialog.accept)
        layout.addWidget(close_btn)
        
        dialog.exec_()

    def clear_completed_tasks(self):
        """清理已完成的任务"""
        completed_tasks = [
            task for task in self.task_manager.get_all_tasks()
            if task['status'] in ['completed', 'failed']
        ]
        
        if not completed_tasks:
            QMessageBox.information(self, "清理任务", "没有可清理的任务")
            return
        
        reply = QMessageBox.question(
            self,
            "清理任务",
            f"确定要清理 {len(completed_tasks)} 个已完成的任务吗？",
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            # 从表格中移除任务
            for task in completed_tasks:
                for row in range(self.task_table.rowCount()):
                    if self.task_table.item(row, 0).text() == task['task_id']:
                        self.task_table.removeRow(row)
                        break
            
            # 从任务管理器中移除任务
            for task in completed_tasks:
                self.task_manager.remove_task(task['task_id'])
            
            self.statusBar().showMessage(f"已清理 {len(completed_tasks)} 个任务")

    def pause_task(self, task_id: str):
        """暂停任务"""
        task = self.task_manager.get_task(task_id)
        if task:
            task['status'] = 'paused'
            self.statusBar().showMessage(f"任务 {task_id} 已暂停")

    def resume_task(self, task_id: str):
        """继续任务"""
        task = self.task_manager.get_task(task_id)
        if task:
            task['status'] = 'pending'
            self.task_queue.put(task_id)
            self.statusBar().showMessage(f"任务 {task_id} 已继续")

    def toggle_task(self, task_id: str):
        """切换任务状态"""
        task = self.task_manager.get_task(task_id)
        if task:
            if task['status'] == 'processing':
                task['status'] = 'paused'
            else:
                task['status'] = 'processing'
            self.statusBar().showMessage(f"任务 {task_id} 已切换为 {self.get_status_text(task['status'])}")

    def load_recent_dirs(self):
        """加载最近使用的目录"""
        self.recent_dirs = {'input': [], 'output': []}
        
        if self.recent_dirs_file.exists():
            try:
                with open(self.recent_dirs_file, 'r', encoding='utf-8') as f:
                    self.recent_dirs = json.load(f)
            except Exception as e:
                print(f"加载最近目录失败: {e}")

    def save_recent_dirs(self):
        """保存最近使用的目录"""
        try:
            self.recent_dirs = {
                'input': self.input_dir.text(),
                'output': self.output_dir.text()
            }
            with open(self.recent_dirs_file, 'w', encoding='utf-8') as f:
                json.dump(self.recent_dirs, f, ensure_ascii=False, indent=2)
        except Exception as e:
            self.logger.error(f"保存目录记录失败: {e}", exc_info=True)

    def add_recent_dir(self, dir_type: str, path: str):
        """添加最近使用的目录"""
        if dir_type not in self.recent_dirs:
            return
        
        # 移除已存在的路径
        if path in self.recent_dirs[dir_type]:
            self.recent_dirs[dir_type].remove(path)
        
        # 添加到开头
        self.recent_dirs[dir_type].insert(0, path)
        
        # 限制数量
        self.recent_dirs[dir_type] = self.recent_dirs[dir_type][:10]
        
        # 保存
        self.save_recent_dirs()

    def show_recent_dirs_menu(self, dir_type: str):
        """显示最近使用的目录菜单"""
        menu = QMenu(self)
        
        for path in self.recent_dirs.get(dir_type, []):
            action = menu.addAction(path)
            action.triggered.connect(lambda checked, p=path: self.set_directory(dir_type, p))
        
        if menu.actions():
            menu.addSeparator()
        menu.addAction("浏览...").triggered.connect(lambda: self.select_directory(dir_type))
        
        # 获取按钮位置
        button = self.findChild(QPushButton, f"{dir_type}_dir_btn")
        if button:
            menu.exec_(button.mapToGlobal(button.rect().bottomLeft()))

    def set_directory(self, dir_type: str, path: str):
        """设置目录"""
        if dir_type == 'input':
            self.input_dir.setText(path)
            self.update_directory_stats(path)
        else:
            self.output_dir.setText(path)

    def get_all_reason_texts(self) -> Dict[str, str]:
        """获取所有过滤原因的文本映射"""
        return {
            'resolution_too_small': '分辨率过小',
            'low_quality': '图片质量不达标',
            'no_face': '未检测到有效人脸',
            'face_too_small': '人脸比例过小',
            'face_too_large': '人脸比例过大',
            'yaw_out_of_range': '偏航角过大',
            'pitch_out_of_range': '俯仰角过大',
            'too_blurry': '图片模糊',
            'manual': '人工判定',
            'processing_error': '处理出错'
        }

    def apply_filters(self):
        """应用筛选条件"""
        if not hasattr(self, 'current_task_id'):
            return
        
        task = self.task_manager.get_task(self.current_task_id)
        if not task:
            return
    
        # 获取筛选条件
        reason_filter = self.reason_filter.currentText()
    
        # 更新缓存的结果
        self.cached_results['passed'] = [
            (f, r) for f, r in task['results'].items() 
            if r['status'] == 'success'
        ]
    
        self.cached_results['filtered'] = [
            (f, r) for f, r in task['results'].items() 
            if r['status'] != 'success' and (
                reason_filter == "全部" or 
                any(reason_filter in fr['message'] for fr in r['filter_reasons'])
            )
        ]
    
        # 更新统计信息
        self.update_task_stats()
    
        # 加载当前页数据
        self.load_page_data('passed', getattr(self, 'passed_current_page', 1))
        self.load_page_data('filtered', getattr(self, 'filtered_current_page', 1))

    def get_sort_key(self, result, sort_by: str):
        """获取排序键"""
        if sort_by == "文件名":
            return result.filename
        elif sort_by == "处理时间":
            return result.timestamp
        elif sort_by == "人脸比例":
            return result.analysis.get('face_ratio', 0) if result.analysis else 0
        elif sort_by == "模糊度":
            return result.analysis.get('blur', 0) if result.analysis else 0
        return 0

    def update_result_tables_with_data(self, results):
        """使用给定数据更新结果表格"""
        # 计算分页
        page_size = int(self.page_size.currentText())
        total_items = len(results)
        total_pages = max(1, (total_items + page_size - 1) // page_size)
        
        self.current_page = min(getattr(self, 'current_page', 1), total_pages)
        start_idx = (self.current_page - 1) * page_size
        end_idx = min(start_idx + page_size, total_items)
        
        # 更新分页控件
        self.page_info.setText(f"{self.current_page}/{total_pages}")
        self.prev_page.setEnabled(self.current_page > 1)
        self.next_page.setEnabled(self.current_page < total_pages)
        
        # 清空表格
        self.filtered_table.setRowCount(0)
        self.passed_table.setRowCount(0)
        
        current_row = self.task_table.currentRow()
        if current_row >= 0:
            task_id = self.task_table.item(current_row, 0).text()
            
            # 添加当前页的结果
            for filename, result in results[start_idx:end_idx]:
                if result.status != 'success':
                    row = self.filtered_table.rowCount()
                    self.filtered_table.insertRow(row)
                    
                    # 添加缩略图
                    self.filtered_table.setItem(row, 0, QTableWidgetItem(filename))
                    
                    # 添加原因
                    reasons = ', '.join(r.message for r in result.filter_reasons)
                    self.filtered_table.setItem(row, 1, QTableWidgetItem(reasons))
                    
                    # 添加纠正按钮
                    btn = self.create_correct_button(self.filtered_table, row, filename, False)
                    self.filtered_table.setCellWidget(row, 2, btn)
                else:
                    row = self.passed_table.rowCount()
                    self.passed_table.insertRow(row)
                    
                    # 添加缩略图
                    self.passed_table.setItem(row, 0, QTableWidgetItem(filename))
                    
                    # 添加纠正按钮
                    btn = self.create_correct_button(self.passed_table, row, filename, True)
                    self.passed_table.setCellWidget(row, 1, btn)

    def on_task_selected(self):
        """处理任务选择事件"""
        try:
            current_row = self.task_table.currentRow()
            if current_row >= 0:
                task_id = self.task_table.item(current_row, 0).text()
                # 获取完整的task_id
                sql = "SELECT * FROM tasks"
                tasks = DBConnection.execute(sql, fetch=True)
                for task in tasks   :
                    if task['task_id'].startswith(task_id):
                        self.current_task_id = task['task_id']
                        self.load_task_results(task['task_id'])
                        break
            
        except Exception as e:
            self.logger.error(f"处理任务选择失败: {e}", exc_info=True)

    def load_task_results(self, task_id: str):
        """加载任务处理结果"""
        try:
            total_start = time.time()
            self.logger.info("开始加载任务处理结果...")

            # 1. 加载通过的结果
            passed_start = time.time()
            sql = """
                SELECT r.*
                FROM success_results r 
                WHERE r.task_id = %s 
                ORDER BY r.id DESC
            """
            passed_results = DBConnection.execute(sql, (task_id,), fetch=True)

            # 2. 加载未通过的结果
            failed_start = time.time()
            sql = """
                SELECT r.*
                FROM failed_results r 
                WHERE r.task_id = %s 
                ORDER BY r.id DESC
            """
            failed_results = DBConnection.execute(sql, (task_id,), fetch=True)

            # 5. 更新统计信息
            stats_start = time.time()
            total = len(passed_results) + len(failed_results)
            pass_rate = len(passed_results) / total * 100 if total > 0 else 0
            stats_text = (
                f"总计: {total} 张图片 | "
                f"通过: {len(passed_results)} ({pass_rate:.1f}%) | "
                f"未通过: {len(failed_results)} ({100-pass_rate:.1f}%)"
            )
            self.stats_info.setText(stats_text)

        except Exception as e:
            self.logger.error(f"加载任务处理结果失败: {e}", exc_info=True)

    def preview_image_from_table(self, row: int, column: int):
        """从表格双击预览图片"""
        if column != 0:  # 只处理第一列（缩略图列）
            return
        
        table = self.sender()
        filename = table.item(row, 0).text()
        
        # 获取当前任务
        if hasattr(self, 'current_task_id'):
            task = self.task_manager.get_task(self.current_task_id)
            if task and filename in task['results']:
                result = task['results'][filename]
                
                # 优先使用处理后的路径
                image_path = result['processed_path']
                if not image_path or not os.path.exists(image_path):
                    image_path = os.path.join(task['input_dir'], filename)
                
                if os.path.exists(image_path):
                    print(f"预览图片: {image_path}")
                    dialog = ImagePreviewDialog(image_path, self)
                    dialog.exec_()
                else:
                    print(f"图片不存在: {image_path}")
                    QMessageBox.warning(self, "错误", "图片文件不存在")

    def change_page(self, table_type: str, delta: int):
        """切换页面"""
        current_page = getattr(self, f"{table_type}_current_page", 1)
        total_items = len(self.cached_results[table_type])
        page_size = getattr(self, f"{table_type}_page_size")
        total_pages = (total_items + page_size - 1) // page_size
        
        new_page = max(1, min(current_page + delta, total_pages))
        if new_page != current_page:
            setattr(self, f"{table_type}_current_page", new_page)
            self.load_page_data(table_type, new_page)

    def go_to_page(self, table_type: str, page: int):
        """跳转到指定页面"""
        setattr(self, f"{table_type}_current_page", page)
        self.load_page_data(table_type, page)

    def go_to_last_page(self, table_type: str):
        """跳转到最后一页"""
        total_items = len(self.cached_results[table_type])
        page_size = getattr(self, f"{table_type}_page_size")
        total_pages = (total_items + page_size - 1) // page_size
        self.go_to_page(table_type, total_pages)

    def pause_current_task(self):
        """暂停当前任务"""
        current_row = self.task_table.currentRow()
        if current_row >= 0:
            task_id = self.task_table.item(current_row, 0).text()
            self.pause_task(task_id)
            self.pause_btn.setEnabled(False)
            self.resume_btn.setEnabled(True)

    def resume_current_task(self):
        """继续当前任务"""
        current_row = self.task_table.currentRow()
        if current_row >= 0:
            task_id = self.task_table.item(current_row, 0).text()
            self.resume_task(task_id)
            self.pause_btn.setEnabled(True)
            self.resume_btn.setEnabled(False)

    def update_control_buttons(self, task):
        """更新控制按钮状态"""
        if task['status'] == 'processing':
            self.start_btn.setEnabled(False)
            self.pause_btn.setEnabled(True)
            self.resume_btn.setEnabled(False)
        elif task['status'] == 'paused':
            self.start_btn.setEnabled(False)
            self.pause_btn.setEnabled(False)
            self.resume_btn.setEnabled(True)
        else:
            self.start_btn.setEnabled(True)
            self.pause_btn.setEnabled(False)
            self.resume_btn.setEnabled(False)

    def on_task_cell_double_clicked(self, row: int, column: int):
        """处理任务表格双击事件"""
        if column in [6, 7]:  # 输入/输出目录列
            dir_path = self.task_table.item(row, column).text()
            if os.path.exists(dir_path):
                try:
                    if sys.platform == 'win32':
                        os.startfile(dir_path)
                    elif sys.platform == 'darwin':
                        subprocess.run(['open', dir_path])
                    else:
                        subprocess.run(['xdg-open', dir_path])
                except Exception as e:
                    self.logger.error(f"打开目录失败: {e}", exc_info=True)
                    QMessageBox.warning(self, "错误", f"打开目录失败: {str(e)}")

    def save_tasks(self):
        """保存任务数据"""
        try:
            self.tasks_file.parent.mkdir(parents=True, exist_ok=True)
            tasks_data = []
            sql = "SELECT * FROM tasks" 
            tasks = DBConnection.execute(sql, fetch=True)
            for task in tasks.values():
                task_dict = task.to_dict()
                # 确保路径是相对路径
                task_dict['input_dir'] = os.path.abspath(task_dict['input_dir'])
                task_dict['output_dir'] = os.path.abspath(task_dict['output_dir'])
                tasks_data.append(task_dict)
            
            with open(self.tasks_file, 'w', encoding='utf-8') as f:
                json.dump(tasks_data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"保存任务数据失败: {e}")

    def closeEvent(self, event):
        """关闭窗口时的处理"""
        try:
            # 停止任务管理器
            if hasattr(self, 'task_manager'):
                self.task_manager.stop()
                
            event.accept()
            
        except Exception as e:
            self.logger.error(f"关闭窗口失败: {e}", exc_info=True)
            event.accept()

    def restore_window_state(self):
        """恢复窗口状态"""
        try:
            state_file = self.config_dir / 'window_state.json'
            if state_file.exists():
                with open(state_file, 'r') as f:
                    settings = json.load(f)
                
                # 恢复窗口几何形状和状态
                self.restoreGeometry(QByteArray.fromBase64(settings['geometry'].encode()))
                self.restoreState(QByteArray.fromBase64(settings['state'].encode()))
                
                # 如果之前是最大化，则最大化显示
                if settings.get('maximized', True):
                    self.showMaximized()
        except Exception as e:
            print(f"恢复窗口状态失败: {e}")
            self.showMaximized()  # 默认最大化显示

    def create_correct_button(self, table: QTableWidget, row: int, filename: str, is_passed: bool) -> QPushButton:
        """创建纠正按钮"""
        btn = QPushButton("纠正" if is_passed else "通过")
        btn.setFixedWidth(60)
        btn.setStyleSheet("""
            QPushButton {
                background-color: #0078d4;
                color: white;
                border: none;
                padding: 4px 8px;
                border-radius: 2px;
                font-size: 12px;
            }
            QPushButton:hover {
                background-color: #106ebe;
            }
        """)
        btn.clicked.connect(lambda: self.correct_result(filename, is_passed))
        return btn

    def correct_to_filtered(self, task_id: str, filename: str):
        """将图片从通过改为未通过"""
        task = self.task_manager.get_task(task_id)
        if task and filename in task['results']:
            result = task['results'][filename]
            if result['processed_path']:
                try:
                    # 移动文件
                    new_path = os.path.join(os.path.dirname(task['output_dir']), 'filtered', filename)
                    os.makedirs(os.path.dirname(new_path), exist_ok=True)
                    shutil.move(result['processed_path'], new_path)
                    result['processed_path'] = new_path
                    result['status'] = 'filtered'
                    result['filter_reasons'] = [FilterReason('manual', '人工判定')]
                    print(f"已将 {filename} 移动到未通过目录")
                except Exception as e:
                    print(f"移动文件失败: {e}")
                    QMessageBox.warning(self, "错误", f"移动文件失败: {str(e)}")

    def correct_to_passed(self, task_id: str, filename: str):
        """将图片从未通过改为通过"""
        task = self.task_manager.get_task(task_id)
        if task and filename in task['results']:
            result = task['results'][filename]
            if result['processed_path']:
                try:
                    # 移动文件
                    new_path = os.path.join(os.path.dirname(task['output_dir']), 'passed', filename)
                    os.makedirs(os.path.dirname(new_path), exist_ok=True)
                    shutil.move(result['processed_path'], new_path)
                    result['processed_path'] = new_path
                    result['status'] = 'success'
                    result['filter_reasons'] = []
                    print(f"已将 {filename} 移动到通过目录")
                except Exception as e:
                    print(f"移动文件失败: {e}")
                    QMessageBox.warning(self, "错误", f"移动文件失败: {str(e)}")

    def get_reason_text(self, code: str) -> str:
        """获取原因文本"""
        reason_map = {
            'resolution_too_small': '分辨率过小',
            'low_quality': '图片质量不达标',
            'no_face': '未检测到有效人脸',
            'face_too_small': '人脸比例过小',
            'face_too_large': '人脸比例过大',
            'yaw_out_of_range': '偏航角过大',
            'pitch_out_of_range': '俯仰角过大',
            'too_blurry': '图片模糊',
            'manual': '人工判定',
            'processing_error': '处理出错'
        }
        return reason_map.get(code, code)

    def update_task_results(self, task_id: str):
        """更新任务结果显示"""
        self.current_task_id = task_id
        task = self.task_manager.get_task(task_id)
        if not task:
            return
        
        # 清空表格
        self.filtered_table.setRowCount(0)
        self.passed_table.setRowCount(0)
        
        # 设置行高
        self.filtered_table.verticalHeader().setDefaultSectionSize(80)  # 增加行高
        self.passed_table.verticalHeader().setDefaultSectionSize(80)    # 增加行高
        
        # 添加结果到表格
        for filename, result in task['results'].items():
            if result['status'] == 'filtered' or result['status'] == 'failed':
                row = self.filtered_table.rowCount()
                self.filtered_table.insertRow(row)
                
                # 文件名列（带缩略图）
                name_item = QTableWidgetItem(filename)
                self.filtered_table.setItem(row, 0, name_item)
                
                # 原因列
                reasons = ', '.join(r['message'] for r in result['filter_reasons'])
                self.filtered_table.setItem(row, 1, QTableWidgetItem(reasons))
                
                # 添加纠正按钮
                btn = self.create_correct_button(self.filtered_table, row, filename, False)
                self.filtered_table.setCellWidget(row, 2, btn)
                if result['status'] == 'success':
                    row = self.passed_table.rowCount()
                    self.passed_table.insertRow(row)
                    
                # 文件名列（带缩略图）
                name_item = QTableWidgetItem(filename)
                self.passed_table.setItem(row, 0, name_item)
                
                # 分析结果列
                analysis_text = self.format_analysis_result(result.analysis)
                self.passed_table.setItem(row, 1, QTableWidgetItem(analysis_text))
                
                # 操作列（小按钮）
                btn = self.create_correct_button(self.passed_table, row, filename, True)
                self.passed_table.setCellWidget(row, 2, btn)

    def format_analysis_result(self, analysis: dict) -> str:
        """格式化分析结果"""
        if not analysis:
            return "无分析结果"
        
        parts = []
        if 'quality_score' in analysis:
            parts.append(f"质量分数: {analysis['quality_score']:.2f}")
        if 'face_ratio' in analysis:
            parts.append(f"人脸比例: {analysis['face_ratio']:.1%}")
        if 'blur' in analysis:
            parts.append(f"清晰度: {analysis['blur']:.1f}")
        
        return ' | '.join(parts) if parts else "无详细信息"

    def update_tasks(self):
        """更新任务状态"""
        try:
            # 更新任务表格
            for row in range(self.task_table.rowCount()):
                task_id = self.task_table.item(row, 0).text()
                task = self.task_manager.get_task(task_id)
                if task:
                    # 更新状态
                    self.task_table.item(row, 1).setText(self.get_status_text(task['status']))
                    
                    # 更新进度
                    self.task_table.item(row, 2).setText(f"{task['progress'] * 100:.1f}%")
                    
                    # 更新处理数量
                    self.task_table.item(row, 3).setText(f"{task['processed_files']}/{task['total_files']}")
                    
                    # 更新用时
                    self.task_table.item(row, 4).setText(f"{task['duration']:.1f}秒")
                    
                    # 更新通过率
                    passed_count = sum(1 for r in task['results'].values() if r['status'] == 'success')
                    total_count = len(task['results'])
                    pass_rate = (passed_count / total_count * 100) if total_count > 0 else 0
                    self.task_table.item(row, 5).setText(f"{pass_rate:.1f}%")
                    
                    # 更新操作按钮
                    operation_widget = self.task_table.cellWidget(row, 8)
                    if operation_widget:
                        pause_btn = operation_widget.layout().itemAt(0).widget()
                        if task['status'] == 'processing':
                            pause_btn.setText("暂停")
                        else:
                            pause_btn.setText("继续")
                    
                    # 如果是当前选中的任务，更新结果显示
                    if row == self.task_table.currentRow():
                        self.update_task_results(task_id)
            
            # 更新状态栏
            sql = "SELECT * FROM tasks" 
            tasks = DBConnection.execute(sql, fetch=True)
            running_tasks = sum(1 for task in tasks.values() 
                              if task['status'] == 'processing')
            if running_tasks > 0:
                self.statusBar().showMessage(f"正在处理 {running_tasks} 个任务")
            else:
                self.statusBar().showMessage("就绪")
            
        except Exception as e:
            print(f"更新任务状态失败: {e}")
            self.statusBar().showMessage(f"更新失败: {str(e)}")

    def refresh_view(self):
        """刷新界面"""
        try:
            # 更新任务表格
            for row in range(self.task_table.rowCount()):
                task_id = self.task_table.item(row, 0).text()
                task = self.task_manager.get_task(task_id)
                if task:
                    # 更新状态和进度
                    self.task_table.item(row, 1).setText(self.get_status_text(task['status']))
                    self.task_table.item(row, 2).setText(f"{task['progress'] * 100:.1f}%")
                    self.task_table.item(row, 3).setText(f"{task['processed_files']}/{task['total_files']}")
                    self.task_table.item(row, 4).setText(f"{task['duration']:.1f}秒")
                    
                    # 只有在处理中且有新结果时才更新统计信息
                    if task['status'] == 'processing' and task['processed_files'] > 0:
                        if hasattr(self, 'current_task_id') and self.current_task_id == task_id:
                            self.update_task_stats()
                    
                    # 更新按钮状态
                    operation_widget = self.task_table.cellWidget(row, 8)
                    if operation_widget:
                        pause_btn = operation_widget.layout().itemAt(0).widget()
                        pause_btn.setText("暂停" if task['status'] == 'processing' else "继续")
            
        except Exception as e:
            self.logger.error(f"刷新界面失败: {e}", exc_info=True)

    def setup_table(self, table: QTableWidget, is_passed: bool):
        """设置表格"""
        try:
            self.logger.info(f"开始设置表格: {'通过' if is_passed else '未通过'}")
            
            # 设置列
            if is_passed:
                columns = ['缩略图', '文件名', '尺寸', '大小', '质量分数', '详细分数', '人脸比例', '操作']
            else:
                columns = ['缩略图', '文件名', '尺寸', '大小', '过滤原因', '备注', '操作']
            
            table.setColumnCount(len(columns))
            table.setHorizontalHeaderLabels(columns)
            
            # 设置列宽
            header = table.horizontalHeader()
            
            # 缩略图列
            header.setSectionResizeMode(0, QHeaderView.Fixed)
            table.setColumnWidth(0, 120)
            
            # 文件名列
            header.setSectionResizeMode(1, QHeaderView.Fixed)
            table.setColumnWidth(1, 200)
            
            # 尺寸列
            header.setSectionResizeMode(2, QHeaderView.Fixed)
            table.setColumnWidth(2, 100)
            
            # 大小列
            header.setSectionResizeMode(3, QHeaderView.Fixed)
            table.setColumnWidth(3, 80)
            
            if is_passed:
                # 质量分数列
                header.setSectionResizeMode(4, QHeaderView.Fixed)
                table.setColumnWidth(4, 100)
                
                # 详细分数列
                header.setSectionResizeMode(5, QHeaderView.Fixed)
                table.setColumnWidth(5, 200)
                
                # 人脸比例列
                header.setSectionResizeMode(6, QHeaderView.Fixed)
                table.setColumnWidth(6, 100)
                
                # 操作列
                header.setSectionResizeMode(7, QHeaderView.Fixed)
                table.setColumnWidth(7, 200)
            else:
                # 过滤原因列
                header.setSectionResizeMode(4, QHeaderView.Fixed)
                table.setColumnWidth(4, 200)
                
                # 备注列
                header.setSectionResizeMode(5, QHeaderView.Stretch)
                
                # 操作列
                header.setSectionResizeMode(6, QHeaderView.Fixed)
                table.setColumnWidth(6, 120)
            
            # 设置表格属性
            table.setSelectionBehavior(QTableWidget.SelectRows)
            table.setSelectionMode(QTableWidget.SingleSelection)
            table.setEditTriggers(QTableWidget.NoEditTriggers)
            table.verticalHeader().setVisible(False)
            
            # 设置缩略图代理
            table.setItemDelegateForColumn(0, ThumbnailDelegate(self))
            
            # 连接双击信号
            table.cellDoubleClicked.connect(
                lambda row, col: self.preview_image(table, row) if col == 0 else None
            )
            
            # 设置行高
            table.verticalHeader().setDefaultSectionSize(120)
            
            # 设置表格样式
            table.setStyleSheet("""
                QTableWidget {
                    gridline-color: #d6d6d6;
                    background-color: white;
                    alternate-background-color: #f8f9fa;
                    selection-background-color: #0078d4;
                    selection-color: white;
                    color: black;
                }
                QTableWidget::item {
                    padding: 5px;
                    border: none;
                    color: black;
                }
                QHeaderView::section {
                    background-color: #f0f0f0;
                    padding: 5px;
                    border: none;
                    border-right: 1px solid #d6d6d6;
                    border-bottom: 1px solid #d6d6d6;
                    color: black;
                }
            """)
            
        except Exception as e:
            self.logger.error(f"设置表格失败: {e}", exc_info=True)

    def update_table_row(self, table: QTableWidget, row: int, filename: str, result: ProcessResult, is_passed: bool):
        """更新表格行"""
        try:
            self.logger.info(f"开始更新表格行: row={row}, filename={filename}, is_passed={is_passed}")
            
            # 设置缩略图
            table.setItem(row, 0, QTableWidgetItem(filename))
            
            # 设置文件名
            table.setItem(row, 1, QTableWidgetItem(filename))
            
            # 获取图片路径
            image_path = result['processed_path'] or os.path.join(self.current_task['input_dir'], filename)
            
            # 设置尺寸和大小
            try:
                with Image.open(image_path) as img:
                    size = f"{img.width}x{img.height}"
                    table.setItem(row, 2, QTableWidgetItem(size))
                    
                file_size = os.path.getsize(image_path)
                size_text = f"{file_size/1024/1024:.1f} MB"
                table.setItem(row, 3, QTableWidgetItem(size_text))
            except Exception as e:
                self.logger.error(f"获取图片信息失败: {e}")
                table.setItem(row, 2, QTableWidgetItem("未知"))
                table.setItem(row, 3, QTableWidgetItem("未知"))
            
            # 设置操作列
            btn_widget = QWidget()
            btn_layout = QHBoxLayout(btn_widget)
            btn_layout.setContentsMargins(5, 2, 5, 2)
            btn_layout.setSpacing(8)  # 增加按钮间距
            
            if is_passed:
                # 纠正按钮
                correct_btn = QPushButton("纠正")
                correct_btn.clicked.connect(lambda: self.correct_result(filename, True))
                correct_btn.setStyleSheet(self.get_button_style(True))
                btn_layout.addWidget(correct_btn)
                
                # 水平反转按钮
                flip_btn = QPushButton("水平反转")
                flip_btn.clicked.connect(lambda: self.flip_image(filename))
                flip_btn.setStyleSheet(self.get_button_style(True))
                btn_layout.addWidget(flip_btn)
                
                # 预览按钮
                preview_btn = QPushButton("预览")
                preview_btn.clicked.connect(lambda: self.preview_image(image_path))
                preview_btn.setStyleSheet(self.get_button_style(True))
                btn_layout.addWidget(preview_btn)
                
                # 设置操作列
                op_col = table.columnCount() - 1
                self.logger.info(f"设置通过列表操作列: column={op_col}")
                table.setCellWidget(row, op_col, btn_widget)
                
            else:
                # 设置过滤原因和备注
                reason_text = '\n'.join(r.message for r in result.filter_reasons)
                table.setItem(row, 4, QTableWidgetItem(reason_text))
                
                note = '已裁剪' if result.processed_path and '_cropped.' in result.processed_path else '无'
                table.setItem(row, 5, QTableWidgetItem(note))
                
                # 通过按钮放在操作列
                btn_widget = QWidget()
                btn_layout = QHBoxLayout(btn_widget)
                btn_layout.setContentsMargins(5, 2, 5, 2)
                
                pass_btn = QPushButton("通过")
                pass_btn.clicked.connect(lambda: self.correct_result(filename, True))
                pass_btn.setStyleSheet(self.get_button_style(True))
                btn_layout.addWidget(pass_btn)
                
                preview_btn = QPushButton("预览")
                preview_btn.clicked.connect(lambda: self.preview_image(image_path))
                preview_btn.setStyleSheet(self.get_button_style(True))
                btn_layout.addWidget(preview_btn)
                
                table.setCellWidget(row, -1, btn_widget)
            
            self.logger.info(f"表格行更新完成: row={row}")
            
        except Exception as e:
            self.logger.error(f"更新表格行失败: {e}", exc_info=True)

    def update_results(self):
        """更新结果显示"""
        if not hasattr(self, 'current_task_id'):
            return
        
        task = self.task_manager.get_task(self.current_task_id)
        if not task:
            return
        
        # 保存当前滚动位置
        passed_scroll = self.passed_table.verticalScrollBar().value()
        filtered_scroll = self.filtered_table.verticalScrollBar().value()
        
        # 更新数据
        self.update_table_data()
        
        # 恢复滚动位置
        self.passed_table.verticalScrollBar().setValue(passed_scroll)
        self.filtered_table.verticalScrollBar().setValue(filtered_scroll)

    def update_table_data(self):
        """更新表格数据"""
        if not hasattr(self, 'current_task_id'):
            return
        
        task = self.task_manager.get_task(self.current_task_id)
        if not task:
            return
    
        # 从数据库获取成功结果
        sql = "SELECT * FROM success_results where task_id = %s"
        success_results = DBConnection.execute(sql, (self.current_task_id), fetch=True)
        # 从数据库获取未通过结果
        sql = "SELECT * FROM failed_results where task_id = %s"
        failed_results = DBConnection.execute(sql, (self.current_task_id), fetch=True)
        # 更新统计信息
        total = len(success_results) + len(failed_results)
        if total > 0:
            pass_rate = len(success_results) / total * 100
            stats_text = (
                f"总计: {total} 张图片 | "
                f"通过: {len(success_results)} ({pass_rate:.1f}%) | "
                f"未通过: {len(failed_results)} ({100-pass_rate:.1f}%)"
            )
            self.stats_info.setText(stats_text)
            self.logger.info(f"统计信息: {stats_text}")
    
        # 更新分页并加载当前页数据
        self.load_handle_result_data(self.current_task_id)

    def update_table(self, table: QTableWidget, task_id: str, is_passed: bool):
        """更新表格内容"""
        try:
            # 清空表格
            table.setRowCount(0)
            
            # 获取当前页码和每页大小
            table_type = "passed" if is_passed else "filtered"
            current_page = getattr(self, f"{table_type}_current_page", 1)
            page_size = getattr(self, f"{table_type}_page_size_value", 10)
            offset = (current_page - 1) * page_size
            
            # 查询数据
            if is_passed:
                sql = """
                    SELECT r.*, i.thumb_path, i.width, i.height, i.file_size 
                    FROM success_results r
                    LEFT JOIN image_list i ON r.task_id = i.task_id AND r.filename = i.filename
                    WHERE r.task_id = %s
                    ORDER BY r.id DESC
                    LIMIT %s , %s
                """
            else:
                sql = """
                    SELECT r.*, i.thumb_path, i.width, i.height, i.file_size 
                    FROM failed_results r
                    LEFT JOIN image_list i ON r.task_id = i.task_id AND r.filename = i.filename
                    WHERE r.task_id = %s
                    ORDER BY r.id DESC
                    LIMIT %s , %s
                """
            
            results = DBConnection.execute(sql, (task_id, offset, page_size), fetch=True)
            
            # 设置表格行数
            table.setRowCount(len(results))

            # 获取task信息
            task = self.task_manager.get_task(task_id)
            # 填充数据
            for row, result in enumerate(results):
                # 缩略图
                thumb_path = os.path.join(task['output_dir'], "thumb", result['filename'])
                table.setItem(row, 0, QTableWidgetItem(thumb_path))
                
                # 文件名
                table.setItem(row, 1, QTableWidgetItem(result['filename']))
                
                # 如果尺寸为空则获取原图尺寸 
                if result['width'] == 0 or result['height'] == 0:
                    image_path = os.path.join(task['output_dir'],'passed' if is_passed else 'filtered', result['filename'])
                    with Image.open(image_path) as img:
                        size_text = f"{img.width}x{img.height}"
                        table.setItem(row, 2, QTableWidgetItem(size_text))
                else:
                    size_text = f"{result['width']}x{result['height']}"
                    table.setItem(row, 2, QTableWidgetItem(size_text))  
                
                # 大小
                if result['file_size']:
                    size_text = self.format_file_size(result['file_size'])
                    table.setItem(row, 3, QTableWidgetItem(size_text))
                
                if is_passed:
                    # 质量分数
                    quality_score = f"{result['quality_score']:.2f}" if result['quality_score'] else "0.00"
                    table.setItem(row, 4, QTableWidgetItem(quality_score))
                    
                    # 详细分数
                    detail_scores = (
                        f"亮度: {result['brightness_score']:.2f}, "
                        f"对比度: {result['contrast_score']:.2f}, "
                        f"模糊度: {result['blur_score']:.2f}"
                    )
                    table.setItem(row, 5, QTableWidgetItem(detail_scores))
                    
                    # 人脸比例
                    face_ratio = f"{result['face_ratio']:.2f}" if result['face_ratio'] else "0.00"
                    table.setItem(row, 6, QTableWidgetItem(face_ratio))
                    
                    # 操作按钮
                    btn_widget = QWidget()
                    btn_layout = QHBoxLayout(btn_widget)
                    btn_layout.setContentsMargins(5, 2, 5, 2)
                    btn_layout.setSpacing(8)
                    
                    # 纠正按钮
                    correct_btn = QPushButton("纠正")
                    correct_btn.clicked.connect(lambda checked, f=result['filename']: self.correct_result(f, True))
                    correct_btn.setStyleSheet(self.get_button_style(True))
                    btn_layout.addWidget(correct_btn)
                    
                    # 水平反转按钮
                    flip_btn = QPushButton("水平反转")
                    flip_btn.clicked.connect(lambda checked, f=result['filename']: self.horizontal_flip(f))
                    flip_btn.setStyleSheet(self.get_button_style(True))
                    btn_layout.addWidget(flip_btn)
                    
                    table.setCellWidget(row, 7, btn_widget)
                    
                else:
                    # 过滤原因
                    table.setItem(row, 4, QTableWidgetItem(result['filter_message']))
                    
                    # 备注
                    if result['filter_details']:
                        details = json.loads(result['filter_details'])
                        details_text = '; '.join(f"{d.get('code', '')}: {d.get('message', '')}" for d in details)
                        table.setItem(row, 5, QTableWidgetItem(details_text))
                    
                    # 操作按钮
                    btn_widget = QWidget()
                    btn_layout = QHBoxLayout(btn_widget)
                    btn_layout.setContentsMargins(5, 2, 5, 2)
                    btn_layout.setSpacing(8)
                    
                    # 通过按钮
                    pass_btn = QPushButton("通过")
                    pass_btn.clicked.connect(lambda checked, f=result['filename']: self.correct_result(f, False))
                    pass_btn.setStyleSheet(self.get_button_style(True))
                    btn_layout.addWidget(pass_btn)
                    
                    table.setCellWidget(row, 6, btn_widget)
            
        except Exception as e:
            self.logger.error(f"更新表格失败: {e}", exc_info=True)

    def create_results_widget(self) -> QWidget:
        """创建结果显示区域"""
        group = QGroupBox("处理结果")
        layout = QVBoxLayout(group)
        
        # 创建表格布局
        tables_layout = QHBoxLayout()
        
        # 通过组
        passed_group = QGroupBox("通过")
        passed_layout = QVBoxLayout(passed_group)
        
        # 通过表格
        self.passed_table = QTableWidget()
        self.setup_table(self.passed_table, True)
        passed_layout.addWidget(self.passed_table)
        
        # 通过列表分页
        self.passed_page_widget = self.create_page_widget("passed")
        passed_layout.addWidget(self.passed_page_widget)
        
        tables_layout.addWidget(passed_group)
        
        # 未通过组
        filtered_group = QGroupBox("未通过")
        filtered_layout = QVBoxLayout(filtered_group)
        
        # 添加统计信息
        self.stats_info = QLabel()
        filtered_layout.addWidget(self.stats_info)
        
        # 添加表格
        self.filtered_table = QTableWidget()
        self.setup_table(self.filtered_table, False)
        filtered_layout.addWidget(self.filtered_table)
        
        # 未通过列表分页
        self.filtered_page_widget = self.create_page_widget("filtered")
        filtered_layout.addWidget(self.filtered_page_widget)
        
        tables_layout.addWidget(filtered_group)
        
        # 添加表格布局到主布局
        layout.addLayout(tables_layout)
        
        return group

    def create_page_widget(self, table_type: str) -> QWidget:
        """创建分页控件"""
        try:
            # 创建主容器和布局
            widget = QWidget()
            layout = QHBoxLayout(widget)
            layout.setContentsMargins(5, 5, 5, 5)
            layout.setSpacing(8)
            
            # 左侧按钮组
            left_widget = QWidget()
            left_layout = QHBoxLayout(left_widget)
            left_layout.setContentsMargins(0, 0, 0, 0)
            left_layout.setSpacing(5)
            
            # 首页按钮
            first_btn = QPushButton("首页")
            first_btn.setFixedWidth(50)
            first_btn.clicked.connect(lambda: self.go_to_page(table_type, 1))
            left_layout.addWidget(first_btn)
            
            # 上一页按钮
            prev_btn = QPushButton("上一页")
            prev_btn.setFixedWidth(60)
            prev_btn.clicked.connect(lambda: self.prev_page(table_type))
            left_layout.addWidget(prev_btn)
            
            layout.addWidget(left_widget)
            
            # 页码按钮容器
            page_buttons = QWidget()
            page_layout = QHBoxLayout(page_buttons)
            page_layout.setSpacing(5)
            page_layout.setContentsMargins(0, 0, 0, 0)
            setattr(self, f"{table_type}_page_buttons", page_layout)
            layout.addWidget(page_buttons)
            
            # 下一页按钮
            next_btn = QPushButton("下一页")
            next_btn.setFixedWidth(60)
            next_btn.clicked.connect(lambda: self.next_page(table_type))
            layout.addWidget(next_btn)
            
            # 右侧跳转区域
            right_widget = QWidget()
            right_layout = QHBoxLayout(right_widget)
            right_layout.setContentsMargins(0, 0, 0, 0)
            right_layout.setSpacing(5)
            
            # 每页条数选择
            page_size_label = QLabel("每页")
            right_layout.addWidget(page_size_label)
            
            page_size_combo = QComboBox()
            page_size_combo.addItems([str(i) for i in [10, 20, 50, 100]])  # 常用的页面大小选项
            page_size_combo.setCurrentText("10")  # 默认10条
            page_size_combo.setFixedWidth(60)
            page_size_combo.currentTextChanged.connect(
                lambda v: self.change_page_size(table_type, int(v))
            )
            setattr(self, f"{table_type}_page_size", page_size_combo)
            right_layout.addWidget(page_size_combo)
            right_layout.addWidget(QLabel("条"))
            
            # 跳转页码输入框
            right_layout.addWidget(QLabel("跳至"))
            page_input = QSpinBox()
            page_input.setFixedWidth(50)
            page_input.setMinimum(1)
            page_input.setButtonSymbols(QSpinBox.NoButtons)  # 去掉上下按钮
            page_input.setStyleSheet("""
                QSpinBox {
                    border: 1px solid #dee2e6;
                    border-radius: 3px;
                    padding: 5px;
                }
                QSpinBox::up-button, QSpinBox::down-button {
                    width: 0px;
                }
            """)
            page_input.valueChanged.connect(lambda v: self.go_to_page(table_type, v))
            setattr(self, f"{table_type}_page_input", page_input)
            right_layout.addWidget(page_input)
            
            # 总页数标签
            total_label = QLabel()
            setattr(self, f"{table_type}_total_pages", total_label)
            right_layout.addWidget(total_label)
            
            layout.addWidget(right_widget)
            
            # 设置样式
            widget.setStyleSheet("""
                QPushButton {
                    padding: 5px;
                    background-color: #f8f9fa;
                    border: 1px solid #dee2e6;
                    border-radius: 3px;
                }
                QPushButton:hover {
                    background-color: #e9ecef;
                }
                QPushButton:disabled {
                    background-color: #e9ecef;
                    color: #6c757d;
                }
                QComboBox {
                    padding: 5px;
                    border: 1px solid #dee2e6;
                    border-radius: 3px;
                }
            """)
            
            return widget
            
        except Exception as e:
            self.logger.error(f"创建分页控件失败: {e}", exc_info=True)
            return QWidget()  # 返回一个空的 widget 以避免空引用

    def change_page_size(self, table_type: str, size: int):
        """改变每页显示数量"""
        setattr(self, f'{table_type}_page_size_value', size)
        self.go_to_page(table_type, 1)  # 切换到第一页
        self.load_handle_result_data(self.current_task_id)

    def load_handle_result_data(self, task_id: str):
        """加载处理结果数据"""
        if not hasattr(self, 'current_task_id'):
            return

        self.update_table(
            self.passed_table,
            task_id,
            True
        )

        self.update_table(
            self.filtered_table,
            task_id,
            False
        )

    def create_thumbnail(self, image_path: str, size: int = 120) -> QPixmap:
        """创建缩略图"""
        try:
            if not image_path or not os.path.exists(image_path):
                # 返回默认图片
                pixmap = QPixmap(size, size)
                pixmap.fill(Qt.lightGray)
                return pixmap
                
            # 使用PIL打开图片以获取更好的质量
            with Image.open(image_path) as img:
                # 计算缩放比例
                ratio = min(size / img.width, size / img.height)
                new_size = (int(img.width * ratio), int(img.height * ratio))
                
                # 使用高质量的缩放算法
                img = img.resize(new_size, Image.Resampling.LANCZOS)
                
                # 转换为QPixmap
                img_data = img.convert("RGB").tobytes("raw", "RGB")
                qimg = QImage(img_data, img.width, img.height, QImage.Format_RGB888)
                pixmap = QPixmap.fromImage(qimg)
                
                # 如果需要，创建正方形缩略图
                if pixmap.width() != size or pixmap.height() != size:
                    result = QPixmap(size, size)
                    result.fill(Qt.transparent)
                    painter = QPainter(result)
                    x = (size - pixmap.width()) // 2
                    y = (size - pixmap.height()) // 2
                    painter.drawPixmap(x, y, pixmap)
                    painter.end()
                    return result
                    
                return pixmap
            
        except Exception as e:
            self.logger.error(f"创建缩略图失败: {e}", exc_info=True)
            # 返回默认图片
            pixmap = QPixmap(size, size)
            pixmap.fill(Qt.lightGray)
            return pixmap

    def preview_image(self, image_path: str):
        """预览原图"""
        try:
            dialog = ImagePreviewDialog(image_path, self)
            dialog.exec()
        except Exception as e:
            self.logger.error(f"预览图片失败: {e}", exc_info=True)

    def update_current_page_data(self):
        """更新当前页数据"""
        for table_type in ['passed', 'filtered']:
            current_page = getattr(self, f"{table_type}_current_page", 1)
            page_size = getattr(self, f"{table_type}_page_size")
            total_items = len(self.cached_results[table_type])
            
            # 计算当前页应该显示的数据范围
            start_idx = (current_page - 1) * page_size
            end_idx = min(start_idx + page_size, total_items)
            
            # 获取表格当前显示的行数
            table = getattr(self, f"{table_type}_table")
            current_rows = table.rowCount()
            
            # 如果当前页数据不足一页，且有新数据可显示
            if current_rows < page_size and end_idx > start_idx:
                page_results = self.cached_results[table_type][start_idx:end_idx]
                self.update_table(table, page_results, table_type == 'passed')

    def load_page_data(self, table_type: str, page: int):
        """加载指定页的数据"""
        if not hasattr(self, 'current_task_id'):
            return
        
        task = self.task_manager.get_task(self.current_task_id)
        if not task:
            return
    
        # 获取对应的表格
        table = getattr(self, f"{table_type}_table")
        page_size = getattr(self, f"{table_type}_page_size")
    
        # 获取当前页的数据
        is_passed = table_type == 'passed'
        results = [
            (f, r) for f, r in task['results'].items()
            if (r['status'] == 'success') == is_passed
        ]
    
        start_idx = (page - 1) * page_size
        end_idx = start_idx + page_size
        page_results = results[start_idx:end_idx]
    
        # 更新表格
        self.update_table(table, page_results, is_passed)

    def save_task_state(self, task_id: str):
        """保存任务状态"""
        try:
            task = self.task_manager.get_task(task_id)
            if task:
                state = {
                    'task_id': task_id,
                    'input_dir': task['input_dir'],
                    'output_dir': task['output_dir'],
                    'status': task['status'],
                    'progress': task['progress'],
                    'processed_files': task['processed_files'],
                    'total_files': task['total_files'],
                    'results': {
                        filename: {
                            'status': result.status,
                            'processed_path': result.processed_path,
                            'filter_reasons': [
                                {'code': r.code, 'message': r.message}
                                for r in result.filter_reasons
                            ]
                        }
                        for filename, result in task['results'].items()
                    }
                }
                
                state_file = self.config_dir / f'task_{task_id}.json'
                with open(state_file, 'w', encoding='utf-8') as f:
                    json.dump(state, f, ensure_ascii=False, indent=2)
                
                self.logger.info(f"保存任务状态: {task_id}")
        except Exception as e:
            self.logger.error(f"保存任务状态失败: {e}", exc_info=True)

    def load_task_states(self):
        """加载所有任务状态"""
        try:
            for state_file in self.config_dir.glob('task_*.json'):
                try:
                    with open(state_file, 'r', encoding='utf-8') as f:
                        state = json.load(f)
                        
                    # 检查目录是否存在
                    if not os.path.exists(state['input_dir']) or not os.path.exists(state['output_dir']):
                        continue
                        
                    # 恢复任务
                    task = self.task_manager.create_task(
                        state['input_dir'],
                        state['output_dir'],
                        self.config
                    )
                    
                    # 恢复任务状态
                    task['status'] = state['status']
                    task['progress'] = state['progress']
                    task['processed_files'] = state['processed_files']
                    task['total_files'] = state['total_files']
                    
                    # 恢复处理结果
                    for filename, result_data in state['results'].items():
                        result = ProcessResult(filename)
                        result.status = result_data['status']
                        result.processed_path = result_data['processed_path']
                        result.filter_reasons = [
                            FilterReason(r['code'], r['message'])
                            for r in result_data['filter_reasons']
                        ]
                        task['results'][filename] = result
                    
                    # 如果任务未完成，添加到处理队列
                    if task['status'] in ['pending', 'processing']:
                        self.task_manager.task_queue.put(task['task_id'])
                    
                    self.add_task_to_table(task)
                    
                except Exception as e:
                    self.logger.error(f"加载任务状态失败: {state_file}, 错误: {e}", exc_info=True)
                    
        except Exception as e:
            self.logger.error(f"加载任务状态失败: {e}", exc_info=True)

    def create_directory_group(self) -> QWidget:
        """创建目录设置区域"""
        group = QGroupBox("目录设置")
        group.setFixedHeight(100)  # 设置固定高度
        layout = QVBoxLayout(group)
        layout.setContentsMargins(10, 5, 10, 5)  # 减小内边距
        
        # 目录选择区域
        dir_layout = QHBoxLayout()
        dir_layout.setSpacing(10)  # 设置控件间距
        
        # 输入目录
        input_layout = QHBoxLayout()
        input_layout.setSpacing(5)
        input_layout.addWidget(QLabel("输入目录:"))
        self.input_dir = QLineEdit()
        self.input_dir.setReadOnly(True)
        self.input_dir.setFixedWidth(300)  # 限制输入框宽度

        # 读取
        if self.recent_dirs['input']:
            self.input_dir.setText(self.recent_dirs['input'])
        else:
            self.input_dir.setPlaceholderText("点击选择输入目录")
        self.input_dir.mousePressEvent = lambda _: self.select_directory('input')
        input_layout.addWidget(self.input_dir)
        
        # 目录统计信息
        self.input_stats = QLabel()  # 修改为 input_stats
        self.input_stats.setStyleSheet("color: #666;")
        input_layout.addWidget(self.input_stats)
        input_layout.addStretch()
        
        dir_layout.addLayout(input_layout)
        
        # 输出目录
        output_layout = QHBoxLayout()
        output_layout.setSpacing(5)
        output_layout.addWidget(QLabel("输出目录:"))
        self.output_dir = QLineEdit()
        self.output_dir.setReadOnly(True)
        self.output_dir.setFixedWidth(300)  # 限制输入框宽度
        # 如果recent_dirs['output']存在，则设置为recent_dirs['output']
        if self.recent_dirs['output']:
            self.output_dir.setText(self.recent_dirs['output'])
        else:
            self.output_dir.setPlaceholderText("点击选择输出目录")
        self.output_dir.mousePressEvent = lambda _: self.select_directory('output')
        output_layout.addWidget(self.output_dir)
        output_layout.addStretch()
        
        dir_layout.addLayout(output_layout)
        
        # 开始按钮
        start_btn = QPushButton("开始筛选")
        start_btn.setStyleSheet(self.get_button_style(True))
        start_btn.setFixedWidth(100)
        start_btn.clicked.connect(self.start_processing)
        dir_layout.addWidget(start_btn)
        
        layout.addLayout(dir_layout)
        return group

    def start_processing(self):
        """开始处理任务"""
        try:
            input_dir = self.input_dir.text()
            output_dir = self.output_dir.text()
            
            self.logger.info(f"开始创建任务: input_dir={input_dir}, output_dir={output_dir}")
            
            if not input_dir or not output_dir:
                self.logger.warning("输入或输出目录为空")
                QMessageBox.warning(self, "错误", "请选择输入和输出目录")
                return
                
            if not os.path.exists(input_dir):
                self.logger.warning(f"输入目录不存在: {input_dir}")
                QMessageBox.warning(self, "错误", "输入目录不存在")
                return
                
            try:
                # 创建输出目录
                os.makedirs(output_dir, exist_ok=True)
                self.logger.info(f"创建输出目录: {output_dir}")
                
                # 先创建基础任务信息
                self.logger.info("开始创建任务基础信息")
                task = self.task_manager.create_task_base(input_dir, output_dir)

                # 保存图片列表到image_list
                # 创建线程后台运行 
                self.worker_thread = threading.Thread(target=self.task_manager.save_image_list, args=(task['task_id'],))
                self.worker_thread.daemon = True
                self.worker_thread.start()
                
                if not task:
                    self.logger.error("创建任务失败: task_manager.create_task_base 返回 None")
                    QMessageBox.warning(self, "错误", "创建任务失败")
                    return
                    
                self.logger.info(f"任务创建成功: task_id={task['task_id']}")
                
                # 立即添加到任务列表显示
                try:
                    self.logger.info("开始更新任务表格")
                    row = self.task_table.rowCount()
                    self.task_table.insertRow(row)
                    self.task_table.setItem(row, 0, QTableWidgetItem(task["task_id"]))
                    self.task_table.setItem(row, 1, QTableWidgetItem("processing"))
                    self.task_table.setItem(row, 2, QTableWidgetItem("0"))
                    self.task_table.setItem(row, 3, QTableWidgetItem(str(task["total_files"])))
                    self.task_table.setItem(row, 4, QTableWidgetItem(input_dir))
                    self.task_table.setItem(row, 5, QTableWidgetItem(output_dir))
                    
                    self.logger.info("基本信息添加完成，开始创建操作按钮")
                    
                    # 更新操作按钮
                    operation_widget = QWidget()
                    operation_layout = QHBoxLayout(operation_widget)
                    operation_layout.setContentsMargins(5, 0, 5, 0)
                    operation_layout.setSpacing(5)
                    
                    # 创建暂停按钮
                    status_btn = QPushButton("暂停")
                    status_btn.clicked.connect(lambda checked, tid=task["task_id"]: self.toggle_task(tid))
                    status_btn.setFixedWidth(100)
                    status_btn.setStyleSheet("""
                        QPushButton {
                            background-color: #f0f0f0;
                            border: 1px solid #d0d0d0;
                            border-radius: 4px;
                            padding: 4px;
                        }
                        QPushButton:hover {
                            background-color: #e0e0e0;
                        }
                        QPushButton:disabled {
                            background-color: #f8f8f8;
                            color: #a0a0a0;
                        }
                    """)
                    operation_layout.addWidget(status_btn)
                    
                    # 创建删除按钮
                    delete_btn = QPushButton("删除")
                    delete_btn.setFixedWidth(60)
                    delete_btn.clicked.connect(lambda checked, tid=task["task_id"]: self.delete_task(tid))
                    delete_btn.setStyleSheet("""
                        QPushButton {
                            background-color: #ff4d4d;
                            color: white;
                            border: none;
                            border-radius: 4px;
                            padding: 4px;
                        }
                        QPushButton:hover {
                            background-color: #ff3333;
                        }
                    """)
                    operation_layout.addWidget(delete_btn)
                    
                    # 设置操作列
                    self.task_table.setCellWidget(row, 6, operation_widget)
                    self.logger.info("操作按钮创建完成")
                    
                except Exception as e:
                    self.logger.error(f"更新任务表格失败: {e}", exc_info=True)
                    raise
                
                # 保存最近使用的目录
                try:
                    self.recent_dirs['input'] = input_dir
                    self.recent_dirs['output'] = output_dir
                    self.save_recent_dirs()
                    self.logger.info("保存最近使用目录完成")
                except Exception as e:
                    self.logger.error(f"保存最近使用目录失败: {e}", exc_info=True)
            except Exception as e:
                self.logger.error(f"创建任务过程中出错: {e}", exc_info=True)
                QMessageBox.warning(self, "错误", f"创建任务失败: {str(e)}")
            
        except Exception as e:
            self.logger.error(f"开始处理失败: {e}", exc_info=True)
            QMessageBox.warning(self, "错误", f"开始处理失败: {str(e)}")

    def update_task_list(self, tasks):
        """更新任务列表"""
        try:
            # 清空表格
            self.task_table.setRowCount(0)
            
            # 设置表格行数
            self.task_table.setRowCount(len(tasks))
            
            # 填充数据
            for row, task in enumerate(tasks):
                # 任务ID
                self.task_table.setItem(row, 0, QTableWidgetItem(task['task_id']))
                
                # 状态
                status_item = QTableWidgetItem(task['status'])
                status_item.setTextAlignment(Qt.AlignCenter)
                self.task_table.setItem(row, 1, status_item)
                
                # 处理进度
                progress = f"{task['processed_files']}/{task['total_files']}"
                progress_item = QTableWidgetItem(progress)
                progress_item.setTextAlignment(Qt.AlignCenter)
                self.task_table.setItem(row, 2, progress_item)
                
                # 总数
                total_item = QTableWidgetItem(str(task['total_files']))
                total_item.setTextAlignment(Qt.AlignCenter)
                self.task_table.setItem(row, 3, total_item)
                
                # 输入目录
                self.task_table.setItem(row, 4, QTableWidgetItem(task['input_dir']))
                
                # 输出目录
                self.task_table.setItem(row, 5, QTableWidgetItem(task['output_dir']))
                
                # 操作列
                btn_widget = QWidget()
                btn_layout = QHBoxLayout(btn_widget)
                btn_layout.setContentsMargins(5, 2, 5, 2)
                btn_layout.setSpacing(8)
                
                # 暂停/继续按钮
                pause_btn = QPushButton("暂停" if task['status'] == 'processing' else "继续")
                pause_btn.setFixedWidth(60)
                pause_btn.setStyleSheet("""
                    QPushButton {
                        background-color: #007bff;
                        color: white;
                        border: none;
                        padding: 5px;
                        border-radius: 3px;
                    }
                    QPushButton:hover {
                        background-color: #0056b3;
                    }
                    QPushButton:disabled {
                        background-color: #6c757d;
                    }
                """)
                pause_btn.clicked.connect(lambda checked, t=task['task_id']: self.toggle_task(t))
                btn_layout.addWidget(pause_btn)
                
                # 删除按钮
                delete_btn = QPushButton("删除")
                delete_btn.setFixedWidth(60)
                delete_btn.setStyleSheet("""
                    QPushButton {
                        background-color: #dc3545;
                        color: white;
                        border: none;
                        padding: 5px;
                        border-radius: 3px;
                    }
                    QPushButton:hover {
                        background-color: #c82333;
                    }
                    QPushButton:disabled {
                        background-color: #6c757d;
                    }
                """)
                delete_btn.clicked.connect(lambda checked, t=task['task_id']: self.delete_task(t))
                btn_layout.addWidget(delete_btn)
                
                # 设置按钮容器
                self.task_table.setCellWidget(row, 6, btn_widget)
                
            # 自动调整列宽
            self.task_table.resizeColumnsToContents()
            
            # 选中第一行
            if self.task_table.rowCount() > 0:
                self.task_table.selectRow(0)
                
        except Exception as e:
            self.logger.error(f"更新任务列表失败: {e}", exc_info=True)

    def _create_task_background(self, input_dir: str, output_dir: str):
        """后台创建任务"""
        try:
            # 创建新任务
            task_id = self.task_manager.create_task(input_dir, output_dir)
            
            # 在主线程中更新UI
            if task_id:
                self.task_created.emit(task_id)
            else:
                self.task_create_failed.emit("创建任务失败")
                
        except Exception as e:
            self.task_create_failed.emit(str(e))
        finally:
            # 关闭进度对话框
            self.progress_dialog_close.emit()

    def create_task_group(self) -> QWidget:
        """创建任务列表区域"""
        group = QGroupBox("任务列表")
        layout = QVBoxLayout(group)
        
        # 创建任务表格
        self.task_table = QTableWidget()
        self.task_table.setColumnCount(7)  # 7列
        self.task_table.setHorizontalHeaderLabels([
            "任务ID", "状态", "处理数量", "总数", "输入目录", "输出目录", "操作"
        ])
        
        # 设置表头样式
        header = self.task_table.horizontalHeader()
        header.setStretchLastSection(False)  # 最后一列不自动拉伸
        header.setDefaultAlignment(Qt.AlignCenter)  # 表头居中对齐
        
        # 设置列宽和对齐方式
        column_configs = [
            ("任务ID", 200, QHeaderView.Fixed, Qt.AlignCenter),      # 缩小任务ID列宽
            ("状态", 100, QHeaderView.Fixed, Qt.AlignCenter),        # 缩小状态列宽
            ("处理数量", 70, QHeaderView.Fixed, Qt.AlignCenter),    # 缩小处理数量列宽
            ("总数", 100, QHeaderView.Fixed, Qt.AlignCenter),        # 缩小总数列宽
            ("输入目录", 200, QHeaderView.Interactive, Qt.AlignLeft | Qt.AlignVCenter),  # 固定初始宽度但可调整
            ("输出目录", 200, QHeaderView.Interactive, Qt.AlignLeft | Qt.AlignVCenter),  # 固定初始宽度但可调整
            ("操作", 250, QHeaderView.Fixed, Qt.AlignCenter)        # 适当调整操作列宽
        ]
        
        for col, (name, width, resize_mode, alignment) in enumerate(column_configs):
            self.task_table.horizontalHeader().setSectionResizeMode(col, resize_mode)
            self.task_table.setColumnWidth(col, width)
            # 设置表头对齐方式
            self.task_table.horizontalHeaderItem(col).setTextAlignment(alignment)
        
        # 设置表格属性
        self.task_table.setSelectionBehavior(QTableWidget.SelectRows)  # 选择整行
        self.task_table.setSelectionMode(QTableWidget.SingleSelection)  # 单选
        self.task_table.setEditTriggers(QTableWidget.NoEditTriggers)  # 不可编辑
        self.task_table.verticalHeader().setVisible(False)  # 隐藏行号
        
        # 设置表格样式
        self.task_table.setStyleSheet("""
            QTableWidget {
                gridline-color: #d6d6d6;
                background-color: white;
                alternate-background-color: #f8f9fa;
                selection-background-color: #0078d4;
                selection-color: white;
            }
            QTableWidget::item {
                padding: 5px;
                border: none;
                color: black;
            }
            QHeaderView::section {
                background-color: #f0f0f0;
                padding: 5px;
                border: none;
                border-bottom: 1px solid #d6d6d6;
                font-weight: bold;
            }
        """)
        
        # 连接信号
        self.task_table.itemSelectionChanged.connect(self.on_task_selected)
        
        layout.addWidget(self.task_table)
        return group

    def get_button_style(self, is_primary: bool = True) -> str:
        """获取统一的按钮样式"""
        if is_primary:
            return """
                QPushButton {
                    background-color: #0078d4;
                    color: white;
                    border: none;
                    border-radius: 4px;
                    padding: 6px 12px;
                    min-width: 80px;
                    max-width: 80px;
                    height: 28px;
                    font-size: 12px;
                }
                QPushButton:hover {
                    background-color: #106ebe;
                }
                QPushButton:pressed {
                    background-color: #005a9e;
                }
                QPushButton:disabled {
                    background-color: #ccc;
                }
            """
        else:
            return """
                QPushButton {
                    background-color: #ffffff;
                    color: #0078d4;
                    border: 1px solid #0078d4;
                    border-radius: 4px;
                    padding: 6px 12px;
                    min-width: 80px;
                    max-width: 80px;
                    height: 28px;
                    font-size: 12px;
                }
                QPushButton:hover {
                    background-color: #f0f8ff;
                }
                QPushButton:pressed {
                    background-color: #e5f1fb;
                }
                QPushButton:disabled {
                    border-color: #ccc;
                    color: #ccc;
                }
            """

    def correct_result(self, filename: str, is_passed: bool):
        """纠正处理结果"""
        try:
            if not hasattr(self, 'current_task_id'):
                return
                
            task = self.task_manager.get_task(self.current_task_id)
            if not task:
                return
                
            # 获取源文件路径
            src_path = os.path.join(task['output_dir'], "passed" if is_passed else "filtered", filename)
            if not os.path.exists(src_path):
                QMessageBox.warning(self, "错误", "源文件不存在")
                return
                
            # 确定目标目录
            target_dir = os.path.join(task['output_dir'], 'filtered' if is_passed else 'passed')
            target_path = os.path.join(target_dir, filename)
            
            if is_passed:
                sql = "delete from success_results where task_id = %s and filename = %s"    
                DBConnection.execute(sql, (task['task_id'], filename))

                insert_sql = "insert into failed_results (task_id, filename, filter_code, filter_message, status) values (%s, %s, %s, %s, %s)"
                DBConnection.execute(insert_sql, (task['task_id'], filename, 'manual', '人工判定', 'failed'))
            else:
                sql = "delete from failed_results where task_id = %s and filename = %s"    
                DBConnection.execute(sql, (task['task_id'], filename))

                insert_sql = "insert into success_results (task_id, filename, face_count, processed_path, quality_score, brightness_score, contrast_score,blur_score, face_ratio, created_at) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
                DBConnection.execute(insert_sql, (task['task_id'], filename, '1', target_path, '60', '60', '60', '60', '0.03', datetime.now().isoformat()))

                # 移动文件
            shutil.move(src_path, target_dir)
            
        except Exception as e:
            self.logger.error(f"纠正结果失败: {e}", exc_info=True)
            QMessageBox.warning(self, "错误", f"纠正结果失败: {str(e)}")

    def flip_image(self, filename: str):
        """水平反转图片"""
        try:
            if not hasattr(self, 'current_task_id'):
                return
                
            task = self.task_manager.get_task(self.current_task_id)
            if not task or filename not in task['results']:
                return
                
            result = task['results'][filename]
            
            # 读取原图
            src_path = os.path.join(task['input_dir'], filename)
            if not os.path.exists(src_path):
                QMessageBox.warning(self, "错误", "源文件不存在")
                return
                
            # 创建反转后的文件名
            base, ext = os.path.splitext(filename)
            flipped_filename = f"{base}_flipped{ext}"
            target_path = os.path.join(task['output_dir'], 'passed', flipped_filename)
            
            # 执行反转
            img = ImageProcessor.imread_with_chinese_path(src_path)
            flipped = cv2.flip(img, 1)  # 1表示水平翻转
            cv2.imwrite(target_path, flipped)
            
            # 添加新的结果
            new_result = ProcessResult(flipped_filename)
            new_result.status = 'success'
            new_result.processed_path = target_path
            task['results'][flipped_filename] = new_result
            
            # 更新任务信息
            task['total_files'] += 1
            task['processed_files'] += 1
            
            # 更新界面
            self.apply_filters()
            
        except Exception as e:
            self.logger.error(f"水平反转失败: {e}", exc_info=True)
            QMessageBox.warning(self, "错误", f"水平反转失败: {str(e)}")

    def on_page_size_changed(self, size: str):
        """处理分页大小变化"""
        self.page_size = int(size)
        self.current_page = 1
        self.apply_filters()

    def check_auto_save(self):
        """检查是否需要自动保存"""
        self.task_manager.auto_save_if_needed()

    def _on_task_created(self, task_id: str):
        """任务创建成功处理"""
        self.progress_dialog.close()
        QMessageBox.information(self, "成功", "任务已创建，开始处理")

    def _on_task_create_failed(self, error: str):
        """任务创建失败处理"""
        self.progress_dialog.close()
        QMessageBox.warning(self, "错误", f"创建任务失败: {error}")

    def _close_progress_dialog(self):
        """关闭进度对话框"""
        if hasattr(self, 'progress_dialog'):
            self.progress_dialog.close()

    def update_task_status(self):
        """更新任务状态"""
        try:
            # 遍历任务表格
            for row in range(self.task_table.rowCount()):
                try:
                    # 获取任务ID
                    task_id = self.task_table.item(row, 0).text()
                    
                    # 获取任务信息
                    sql = "SELECT * FROM tasks"
                    tasks = DBConnection.execute(sql, fetch=True)
                    task = tasks.get(task_id)
                    if not task:
                        continue
                        
                    # 更新状态
                    self.task_table.item(row, 1).setText(task['status'])
                    
                    # 更新处理数量
                    processed = task['processed_files']
                    total = task['total_files']
                    
                    # 更新处理数量列
                    self.task_table.item(row, 2).setText(str(processed))
                    
                    # 更新总数列
                    self.task_table.item(row, 3).setText(str(total))

                    # 更新输入目录列
                    self.task_table.item(row, 4).setText(task['input_dir'])
                    
                    # 更新输出目录列
                    self.task_table.item(row, 5).setText(task['output_dir'])
                    
                    # 更新操作按钮
                    operation_widget = QWidget()
                    operation_layout = QHBoxLayout(operation_widget)
                    operation_layout.setContentsMargins(5, 0, 5, 0)
                    operation_layout.setSpacing(5)
                    
                    # 暂停/继续/完成按钮
                    status = task['status']
                    if status == 'completed':
                        status_btn = QPushButton("完成")
                        status_btn.setEnabled(False)
                    else:
                        status_btn = QPushButton("暂停" if status == 'processing' else "继续")
                        status_btn.clicked.connect(lambda checked, tid=task_id: self.toggle_task(tid))
                    
                    status_btn.setFixedWidth(60)
                    status_btn.setStyleSheet("""
                        QPushButton {
                            background-color: #f0f0f0;
                            border: 1px solid #d0d0d0;
                            border-radius: 4px;
                            padding: 4px;
                        }
                        QPushButton:hover {
                            background-color: #e0e0e0;
                        }
                        QPushButton:disabled {
                            background-color: #f8f8f8;
                            color: #a0a0a0;
                        }
                    """)
                    operation_layout.addWidget(status_btn)
                    
                    # 删除按钮
                    delete_btn = QPushButton("删除")
                    delete_btn.setFixedWidth(60)
                    delete_btn.clicked.connect(lambda checked, tid=task_id: self.delete_task(tid))
                    delete_btn.setStyleSheet("""
                        QPushButton {
                            background-color: #ff4d4d;
                            color: white;
                            border: none;
                            border-radius: 4px;
                            padding: 4px;
                        }
                        QPushButton:hover {
                            background-color: #ff3333;
                        }
                    """)
                    operation_layout.addWidget(delete_btn)
                    
                    # 设置操作列
                    self.task_table.setCellWidget(row, 6, operation_widget)

                    # image_list数量小于total_files
                    # 查询image_list数量
                    sql = "SELECT COUNT(*) FROM image_list WHERE task_id = %s"
                    image_list_count = DBConnection.execute(sql, (task_id,), fetch=True)[0]['COUNT(*)']

                    if image_list_count < task['total_files']:
                        self.task_manager.save_image_list(task_id)
                    
                except Exception as e:
                    self.logger.error(f"更新任务 {task_id} 状态失败: {e}")
                    continue
                
        except Exception as e:
            self.logger.error(f"更新任务状态失败: {e}")

    def format_duration(self, seconds: int) -> str:
        """格式化持续时间"""
        if seconds < 60:
            return f"{seconds}秒"
        elif seconds < 3600:
            return f"{seconds//60}分{seconds%60}秒"
        else:
            return f"{seconds//3600}时{(seconds%3600)//60}分"

    def on_page_changed(self, table_type: str):
        """处理页码变化"""
        try:
            self.logger.info(f"切换{table_type}表格页码")
            
            # 获取相关组件
            if table_type == "passed":
                table = self.passed_table
                page_widget = self.passed_page_widget
                # 获取成功结果
                sql = "SELECT * FROM success_results WHERE task_id = %s"
                results = DBConnection.execute(sql, (self.current_task_id,), fetch=True)
            else:
                table = self.filtered_table
                page_widget = self.filtered_page_widget
                # 获取失败结果
                sql = "SELECT * FROM failed_results WHERE task_id = %s"
                results = DBConnection.execute(sql, (self.current_task_id,), fetch=True)

            # 获取当前页码
            page_combo = page_widget.findChild(QComboBox)
            current_page = int(page_combo.currentText())
            
            # 计算分页数据
            total_items = len(results)
            total_pages = (total_items + self.page_size - 1) // self.page_size
            start_idx = (current_page - 1) * self.page_size
            end_idx = min(start_idx + self.page_size, total_items)
            
            # 清空表格
            table.setRowCount(0)
            
            # 填充当前页数据
            for idx, result in enumerate(results[start_idx:end_idx]):
                try:
                    self.add_result_to_table(table, result['filename'], result, table_type == "passed")
                except Exception as e:
                    self.logger.error(f"添加结果到表格失败: {e}", exc_info=True)
            
            # 更新页码信息
            page_label = page_widget.findChild(QLabel)
            if page_label:
                page_label.setText(f"共 {total_pages} 页")
            
            self.logger.info(f"页码切换完成: 第 {current_page} 页，共 {total_pages} 页")
            
        except Exception as e:
            self.logger.error(f"切换页码失败: {e}", exc_info=True)

    def on_page_size_changed(self, size: int):
        """处理页面大小变化"""
        try:
            self.logger.info(f"修改每页显示数量: {size}")
            self.page_size = size
            
            # 重新加载当前任务的结果
            if hasattr(self, 'current_task_id'):
                self.load_task_results(self.current_task_id)
                
        except Exception as e:
            self.logger.error(f"修改页面大小失败: {e}", exc_info=True)

    def _init_task_table(self):
        """初始化任务表格"""
        try:
            # 设置列
            columns = ['任务ID', '状态', '处理数量', '总数', '输入目录', '输出目录', '操作']
            self.task_table.setColumnCount(len(columns))
            self.task_table.setHorizontalHeaderLabels(columns)
            
            # 设置列宽
            header = self.task_table.horizontalHeader()
            header.setSectionResizeMode(0, QHeaderView.Fixed)  # 任务ID列固定宽度
            self.task_table.setColumnWidth(0, 200)
            
            header.setSectionResizeMode(1, QHeaderView.Fixed)  # 状态列固定宽度
            self.task_table.setColumnWidth(1, 100)
            
            header.setSectionResizeMode(2, QHeaderView.Fixed)  # 处理数量列固定宽度
            self.task_table.setColumnWidth(2, 100)
            
            header.setSectionResizeMode(3, QHeaderView.Fixed)  # 总数列固定宽度
            self.task_table.setColumnWidth(3, 100)
            
            header.setSectionResizeMode(4, QHeaderView.Stretch)  # 输入目录列自动拉伸
            header.setSectionResizeMode(5, QHeaderView.Stretch)  # 输出目录列自动拉伸
            
            header.setSectionResizeMode(6, QHeaderView.Fixed)  # 操作列固定宽度
            self.task_table.setColumnWidth(6, 160)
            
            # 添加双击事件处理
            self.task_table.cellDoubleClicked.connect(self.on_cell_double_clicked)
            
            # 设置表格属性
            self.task_table.setSelectionBehavior(QTableWidget.SelectRows)  # 选择整行
            self.task_table.setSelectionMode(QTableWidget.SingleSelection)  # 单选
            self.task_table.setEditTriggers(QTableWidget.NoEditTriggers)  # 不可编辑
            self.task_table.verticalHeader().setVisible(False)  # 隐藏行号
            
            self.logger.info("任务表格初始化完成")
            
        except Exception as e:
            self.logger.error(f"初始化任务表格失败: {e}", exc_info=True)

    def on_cell_double_clicked(self, row: int, column: int):
        """处理单元格双击事件"""
        try:
            # 只处理输入目录和输出目录列的双击
            if column in [4, 5]:  # 4是输入目录列，5是输出目录列
                path = self.task_table.item(row, column).text()
                if path and os.path.exists(path):
                    # Windows系统
                    if os.name == 'nt':
                        os.startfile(path)
                    # macOS系统
                    elif sys.platform == 'darwin':
                        subprocess.run(['open', path])
                    # Linux系统
                    else:
                        subprocess.run(['xdg-open', path])
                    self.logger.info(f"打开目录: {path}")
                else:
                    QMessageBox.warning(self, "警告", "目录不存在")
                    
        except Exception as e:
            self.logger.error(f"打开目录失败: {e}", exc_info=True)
            QMessageBox.warning(self, "错误", f"打开目录失败: {str(e)}")

    def add_result_to_table(self, table: QTableWidget, row: int, filename: str, result: ProcessResult, is_passed: bool):
        """添加结果到表格"""
        try:
            # 缩略图
            thumb_path = os.path.join(self.current_task['output_dir'], "thumb", filename)
            table.setItem(row, 0, QTableWidgetItem(thumb_path))
            
            # 文件名
            table.setItem(row, 1, QTableWidgetItem(filename))
            
            # 尺寸
            if result.width and result.height:
                table.setItem(row, 2, QTableWidgetItem(f"{result.width}x{result.height}"))
            
            # 大小
            if result.file_size:
                size_text = self.format_file_size(result.file_size)
                table.setItem(row, 3, QTableWidgetItem(size_text))
            
            if is_passed:
                # 质量分数
                quality_score = f"{result.analysis.quality_score:.2f}" if result.analysis.quality_score else "0.00"
                table.setItem(row, 4, QTableWidgetItem(quality_score))
                
                # 详细分数
                detail_scores = (
                    f"亮度: {result.analysis.brightness_score:.2f}, "
                    f"对比度: {result.analysis.contrast_score:.2f}, "
                    f"模糊度: {result.analysis.blur_score:.2f}"
                )
                table.setItem(row, 5, QTableWidgetItem(detail_scores))
                
                # 人脸比例
                face_ratio = f"{result.face_ratio:.2f}" if result.face_ratio else "0.00"
                table.setItem(row, 6, QTableWidgetItem(face_ratio))
                
                # 操作按钮
                btn_widget = QWidget()
                btn_layout = QHBoxLayout(btn_widget)
                btn_layout.setContentsMargins(5, 2, 5, 2)
                btn_layout.setSpacing(8)
                
                # 纠正按钮
                correct_btn = QPushButton("纠正")
                correct_btn.clicked.connect(lambda: self.correct_result(filename, True))
                correct_btn.setStyleSheet(self.get_button_style(True))
                btn_layout.addWidget(correct_btn)
                
                # 水平反转按钮
                flip_btn = QPushButton("水平反转")
                flip_btn.clicked.connect(lambda: self.horizontal_flip(filename))
                flip_btn.setStyleSheet(self.get_button_style(True))
                btn_layout.addWidget(flip_btn)
                
                table.setCellWidget(row, 7, btn_widget)
                
            else:
                # 过滤原因
                if result.filter_reasons:
                    table.setItem(row, 4, QTableWidgetItem(result.filter_reasons[0].message))
                
                # 备注
                if result.filter_reasons:
                    details = [f"{r.code}: {r.message}" for r in result.filter_reasons]
                    table.setItem(row, 5, QTableWidgetItem("; ".join(details)))
                
                # 操作按钮
                btn_widget = QWidget()
                btn_layout = QHBoxLayout(btn_widget)
                btn_layout.setContentsMargins(5, 2, 5, 2)
                btn_layout.setSpacing(8)
                
                # 通过按钮
                pass_btn = QPushButton("通过")
                pass_btn.clicked.connect(lambda: self.correct_result(filename, False))
                pass_btn.setStyleSheet(self.get_button_style(True))
                btn_layout.addWidget(pass_btn)
                
                table.setCellWidget(row, 6, btn_widget)
            
        except Exception as e:
            self.logger.error(f"添加结果到表格失败: {e}", exc_info=True)

    def format_file_size(self, size: int) -> str:
        """格式化文件大小"""
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size < 1024:
                return f"{size:.1f} {unit}"
            size /= 1024
        return f"{size:.1f} TB"

    def horizontal_flip(self, filename: str):
        """水平翻转图片"""
        try:
            self.logger.info(f"开始水平翻转图片: {filename}")
            
            # 获取当前任务信息
            task = self.task_manager.get_task(self.current_task_id)
            if not task:
                self.logger.error("未找到当前任务")
                return
                
            # 构建图片路径
            input_path = os.path.join(task['input_dir'], filename)
            if not os.path.exists(input_path):
                self.logger.error(f"图片不存在: {input_path}")
                QMessageBox.warning(self, "错误", "图片文件不存在")
                return
                
            try:
                # 读取图片
                image = ImageProcessor.imread_with_chinese_path(input_path)
                if image is None:
                    raise Exception("无法读取图片")
                    
                # 水平翻转
                flipped = cv2.flip(image, 1)  # 1表示水平翻转
                
                # 构建输出路径
                name, ext = os.path.splitext(filename)
                output_filename = f"{name}_flipped{ext}"
                output_path = os.path.join(task['input_dir'], output_filename)
                
                # 保存翻转后的图片
                cv2.imwrite(output_path, flipped)
                
                # 更新数据库
                # 1. 复制原图片的成功结果记录
                sql = """
                    INSERT INTO success_results (
                        task_id, filename, processed_path, quality_score,
                        face_count, face_ratio, brightness_score,
                        contrast_score, blur_score
                    )
                    SELECT 
                        task_id, %s, %s, quality_score,
                        face_count, face_ratio, brightness_score,
                        contrast_score, blur_score
                    FROM success_results
                    WHERE task_id = %s AND filename = %s
                """
                DBConnection.execute(sql, (
                    output_filename, output_path,
                    self.current_task_id, filename
                ))
                
                # 2. 添加到图片列表
                sql = """
                    INSERT INTO image_list (task_id, filename, file_size, file_hash, status)
                    VALUES (%s, %s, %s, %s, 'success')
                """
                file_size = os.path.getsize(output_path)
                file_hash = self.task_manager.calculate_file_hash(output_path)
                DBConnection.execute(sql, (
                    self.current_task_id,
                    output_filename,
                    file_size,
                    file_hash
                ))
                
                # 3. 更新任务统计信息
                sql = """
                    UPDATE tasks 
                    SET total_files = total_files + 1,
                        processed_files = processed_files + 1
                    WHERE task_id = %s
                """
                DBConnection.execute(sql, (self.current_task_id,))
                
                # 重新加载结果
                self.load_task_results(self.current_task_id)
                
                self.logger.info(f"水平翻转完成: {output_filename}")
                QMessageBox.information(self, "成功", "图片水平翻转完成")
                
            except Exception as e:
                self.logger.error(f"处理图片失败: {e}", exc_info=True)
                QMessageBox.warning(self, "错误", f"处理图片失败: {str(e)}")
                
        except Exception as e:
            self.logger.error(f"水平翻转操作失败: {e}", exc_info=True)
            QMessageBox.warning(self, "错误", f"操作失败: {str(e)}")

    def preview_image(self, table: QTableWidget, row: int):
        """预览图片"""
        try:
            # 获取文件名
            filename = table.item(row, 1).text()
            if not filename:
                return
                
            # 获取当前任务信息
            task = self.task_manager.get_task(self.current_task_id)
            if not task:
                return
                
            # 构建原图路径
            image_path = os.path.join(task['input_dir'], filename)
            if not os.path.exists(image_path):
                QMessageBox.warning(self, "错误", "原图文件不存在")
                return
                
            # 创建预览对话框
            preview = ImagePreviewDialog(self)
            preview.load_image(image_path)
            preview.exec_()
            
        except Exception as e:
            self.logger.error(f"预览图片失败: {e}", exc_info=True)
            QMessageBox.warning(self, "错误", f"预览失败: {str(e)}")

    def update_task_stats(self, task_id: str):
        """更新任务统计信息"""
        try:
            stats = self.task_manager.get_task_stats(task_id)
            
            # 更新统计标签
            total = stats['total']
            processed = stats['processed']
            success = stats['success']
            failed = stats['failed']
            success_rate = 0 if total == 0 else (success / total) * 100

            # 更新任务列表中已选中任务的已处理数量
            self.task_table.setItem(self.task_table.currentRow(), 2, QTableWidgetItem(str(processed)))
            
            stats_text = (
                f"总计: {total} 张图片 | "
                f"已处理: {processed} 张图片 | "
                f"通过: {success} ({success_rate:.1f}%) | "
                f"未通过: {failed} ({100-success_rate:.1f}%)"
            )
            self.stats_info.setText(stats_text)
        except Exception as e:
            self.logger.error(f"更新统计信息失败: {e}", exc_info=True)

    def update_pagination(self, table_type: str, task_id: str):
        """更新分页信息"""
        if not hasattr(self, 'current_task_id'):
            return
        
        try:
            # 获取总记录数
            if table_type == "passed":
                sql = "SELECT COUNT(*) as count FROM success_results WHERE task_id = %s"
            else:
                sql = "SELECT COUNT(*) as count FROM failed_results WHERE task_id = %s"
            
            result = DBConnection.execute(sql, (task_id,), fetch=True)
            total_items = result[0]['count'] if result else 0
            
            # 获取每页大小
            page_size = getattr(self, f'{table_type}_page_size_value', 10)
            
            # 计算总页数
            total_pages = max(1, (total_items + page_size - 1) // page_size)
            current_page = getattr(self, f'{table_type}_current_page', 1)
            
            # 更新页码输入框范围
            page_input = getattr(self, f"{table_type}_page_input")
            if page_input:
                page_input.setMaximum(total_pages)
                page_input.setValue(current_page)
            
            # 更新总页数显示
            total_label = getattr(self, f"{table_type}_total_pages")
            if total_label:
                total_label.setText(f"/ {total_pages}页")
            
            # 更新页码按钮
            self.update_page_buttons(table_type, current_page, total_pages)
            
        except Exception as e:
            self.logger.error(f"更新分页信息失败: {e}", exc_info=True)

    def update_page_buttons(self, table_type: str, current_page: int, total_pages: int):
        """更新页码按钮"""
        try:
            # 获取页码按钮容器
            page_layout = getattr(self, f"{table_type}_page_buttons")
            if not page_layout:
                return
                
            # 清除现有按钮
            while page_layout.count():
                item = page_layout.takeAt(0)
                if item.widget():
                    item.widget().deleteLater()
                    
            # 计算要显示的页码范围
            if total_pages <= 5:
                start_page = 1
                end_page = total_pages
            else:
                if current_page <= 3:
                    start_page = 1
                    end_page = 5
                elif current_page >= total_pages - 2:
                    start_page = total_pages - 4
                    end_page = total_pages
                else:
                    start_page = current_page - 2
                    end_page = current_page + 2
                    
            # 添加页码按钮
            for page in range(start_page, end_page + 1):
                btn = QPushButton(str(page))
                btn.setFixedWidth(30)
                btn.setCheckable(True)
                btn.setChecked(page == current_page)
                btn.clicked.connect(lambda checked, p=page: self.go_to_page(table_type, p))
                
                # 设置当前页按钮样式
                if page == current_page:
                    btn.setStyleSheet("""
                        QPushButton {
                            background-color: #0078d4;
                            color: white;
                            border: none;
                            padding: 5px;
                            border-radius: 3px;
                        }
                    """)
                else:
                    btn.setStyleSheet("""
                        QPushButton {
                            background-color: #f8f9fa;
                            color: #495057;
                            border: 1px solid #dee2e6;
                            padding: 5px;
                            border-radius: 3px;
                        }
                        QPushButton:hover {
                            background-color: #e9ecef;
                        }
                    """)
                    
                page_layout.addWidget(btn)
                
        except Exception as e:
            self.logger.error(f"更新页码按钮失败: {e}", exc_info=True)

    def go_to_page(self, table_type: str, page: int):
        """跳转到指定页"""
        try:
            # 更新当前页码
            setattr(self, f"{table_type}_current_page", page)
            
            # 更新分页信息
            self.update_pagination(table_type, self.current_task_id)
            
            # 加载数据
            self.load_handle_result_data(self.current_task_id)
            
            self.logger.info(f"跳转到页面: type={table_type}, page={page}")
            
        except Exception as e:
            self.logger.error(f"跳转页面失败: {e}", exc_info=True)

    def prev_page(self, table_type: str):
        """上一页"""
        current_page = getattr(self, f"{table_type}_current_page", 1)
        if current_page > 1:
            self.go_to_page(table_type, current_page - 1)

    def next_page(self, table_type: str):
        """下一页"""
        current_page = getattr(self, f"{table_type}_current_page", 1)
        page_input = getattr(self, f"{table_type}_page_input")
        if page_input and current_page < page_input.maximum():
            self.go_to_page(table_type, current_page + 1)

    def change_page_size(self, table_type: str, size: int):
        """改变每页显示数量"""
        try:
            # 更新每页条数
            setattr(self, f"{table_type}_page_size_value", size)
            
            # 重置当前页为第一页
            setattr(self, f"{table_type}_current_page", 1)
            
            # 更新分页信息
            self.update_pagination(table_type, self.current_task_id)
            
            # 加载数据
            self.load_handle_result_data(self.current_task_id)
            
            self.logger.info(f"改变每页显示数量: type={table_type}, size={size}")
            
        except Exception as e:
            self.logger.error(f"改变每页显示数量失败: {e}", exc_info=True)

    def on_task_table_item_clicked(self, row: int, column: int):
        """处理任务表格点击事件"""
        try:    
            self.current_task_id = self.task_table.item(row, 0).text()
            # 1. 更新统计信息
            self.update_task_stats(self.current_task_id)
            
            # 2. 更新分页信息
            self.update_pagination("passed", self.current_task_id)
            self.update_pagination("filtered", self.current_task_id)

            # 3. 加载当前页数据(未通过的图片列表)
            self.load_handle_result_data(self.current_task_id)
        
        except Exception as e:
            self.logger.error(f"处理任务表格点击事件失败: {e}", exc_info=True)


    def on_task_table_double_clicked(self, row: int, column: int):
        """处理任务表格双击事件"""
        try:
            # 只处理输入目录(4)和输出目录(5)列的双击
            if column not in [4, 5]:
                return
                
            # 获取目录路径
            path = self.task_table.item(row, column).text()
            if not path:
                return
                
            # 确保目录存在
            if not os.path.exists(path):
                QMessageBox.warning(self, "警告", f"目录不存在: {path}")
                return
                
            # 根据操作系统打开文件夹
            if sys.platform == 'win32':
                os.startfile(path)
            elif sys.platform == 'darwin':  # macOS
                subprocess.run(['open', path])
            else:  # Linux
                subprocess.run(['xdg-open', path])
                
        except Exception as e:
            self.logger.error(f"打开目录失败: {e}", exc_info=True)
            QMessageBox.warning(self, "错误", f"打开目录失败: {str(e)}")

class ThumbnailDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.thumbnail_size = 120
        self.parent_window = parent
        self.logger = logging.getLogger(__name__)
        
    def paint(self, painter, option, index):
        try:
            # 直接获取缩略图路径
            thumb_path = index.data()
            if not thumb_path or not os.path.exists(thumb_path):
                return
                
            # 加载缩略图
            pixmap = QPixmap(thumb_path)
            if pixmap.isNull():
                return
                
            # 计算绘制区域
            target_rect = option.rect
            if pixmap.width() > target_rect.width() or pixmap.height() > target_rect.height():
                pixmap = pixmap.scaled(
                    target_rect.size(), 
                    Qt.KeepAspectRatio, 
                    Qt.SmoothTransformation
                )
            
            # 居中绘制
            x = target_rect.x() + (target_rect.width() - pixmap.width()) // 2
            y = target_rect.y() + (target_rect.height() - pixmap.height()) // 2
            painter.drawPixmap(x, y, pixmap)
            
        except Exception as e:
            self.logger.error(f"绘制缩略图失败: {e}", exc_info=True)
